diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 86c5e6d5acb..f49bb74fe39 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -8,8 +8,11 @@ on: - "**.md" pull_request: - paths-ignore: - - "**.md" + paths: + - .github/workflows/*playwright*.yml + - apps/** + - packages/** + - api/** merge_group: branches: [main] # Concurrency is used to cancel other currently-running jobs, to preserve @@ -29,6 +32,11 @@ jobs: playwright: name: Playwright runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + shardIndex: [1, 2, 3, 4] + shardTotal: [4] env: # Use native docker command within docker compose COMPOSE_DOCKER_CLI_BUILD: 1 @@ -69,28 +77,49 @@ jobs: - name: Install Playwright Browsers run: npx playwright install chromium webkit --with-deps - - name: Run Chromium Tests - run: pnpm run e2e:playwright:chromium + - name: Run Tests + run: pnpm run e2e:playwright --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} - uses: actions/upload-artifact@v4 if: always() with: - name: chromium-report - path: ./apps/playwright/playwright-report/ - retention-days: 30 + name: blob-report-${{ matrix.shardIndex }} + path: ./apps/playwright/blob-report + retention-days: 1 - - name: Run Webkit Tests - run: pnpm run e2e:playwright:webkit - - uses: actions/upload-artifact@v4 - if: always() - with: - name: webkit-report - path: ./apps/playwright/playwright-report/ - retention-days: 30 + merge-reports: + # Merge reports after playwright-tests, even if some shards have failed + if: ${{ !cancelled() }} + needs: [playwright] + runs-on: ubuntu-latest + env: + PNPM_VERSION: "9.12.3" + steps: + - uses: pnpm/action-setup@v4 + with: + version: ${{ env.PNPM_VERSION }} + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: ".nvmrc" + cache: pnpm + + # Fix some issue with cache in setup-node + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Download blob reports from GitHub Actions Artifacts + uses: actions/download-artifact@v4 + with: + path: all-blob-reports + pattern: blob-report-* + merge-multiple: true - - name: Check status of containers - if: failure() - run: docker compose ps + - name: Merge into HTML Report + run: npx playwright merge-reports --reporter html ./all-blob-reports - - name: "Check logs: web server container" - if: failure() - run: docker compose logs webserver + - name: Upload HTML report + uses: actions/upload-artifact@v4 + with: + name: html-report--attempt-${{ github.run_attempt }} + path: playwright-report + retention-days: 14 diff --git a/api/app/Builders/PoolBuilder.php b/api/app/Builders/PoolBuilder.php index d286909b559..88977c963f7 100644 --- a/api/app/Builders/PoolBuilder.php +++ b/api/app/Builders/PoolBuilder.php @@ -137,14 +137,16 @@ public function publishingGroups(?array $publishingGroups): self return $this->whereIn('publishing_group', $publishingGroups); } - public function streams(?array $streams): self + public function whereWorkStreamsIn(?array $streams): self { if (empty($streams)) { return $this; } - return $this->whereIn('stream', $streams); + return $this->whereHas('workStream', function ($query) use ($streams) { + $query->whereIn('id', $streams); + }); } public function whereClassifications(?array $classifications): self @@ -168,7 +170,7 @@ public function whereClassifications(?array $classifications): self /** * Custom sort to handle issues with how laravel aliases * aggregate selects and orderBys for json fields in `lighthouse-php` - * + * The column used in the orderBy is `table_aggregate_column->property` * But is actually aliased to snake case `table_aggregate_columnproperty` */ @@ -184,6 +186,25 @@ public function orderByTeamDisplayName(?array $args): self return $this; } + /** + * Custom sort to handle issues with how laravel aliases + * aggregate selects and orderBys for json fields in `lighthouse-php` + * + * The column used in the orderBy is `table_aggregate_column->property` + * But is actually aliased to snake case `table_aggregate_columnproperty` + */ + public function orderByWorkStreamName(?array $args): self + { + $order = $args['order'] ?? null; + $locale = $args['locale'] ?? null; + + if ($order && $locale) { + return $this->withMax('workStream', 'name->'.$locale)->orderBy('work_stream_max_name'.$locale, $order); + } + + return $this; + } + public function orderByPoolBookmarks(?array $args): self { /** @var \App\Models\User|null */ diff --git a/api/app/Casts/LocalizedString.php b/api/app/Casts/LocalizedString.php new file mode 100644 index 00000000000..a4452a70ff5 --- /dev/null +++ b/api/app/Casts/LocalizedString.php @@ -0,0 +1,40 @@ + $attributes + */ + public function get(Model $model, string $key, mixed $value, array $attributes): mixed + { + if (is_null($value) || $value === '' || $value === 'null') { + return null; + } + + $decodedValue = is_array($value) ? $value : json_decode($value, true); + $locale = App::getLocale() ?? 'en'; + + return [ + ...$decodedValue, + 'localized' => $decodedValue[$locale] ?? null, + ]; + } + + /** + * Prepare the given value for storage. + * + * @param array $attributes + */ + public function set(Model $model, string $key, mixed $value, array $attributes): mixed + { + return json_encode($value); + } +} diff --git a/api/app/Console/Commands/MigratePoolStream.php b/api/app/Console/Commands/MigratePoolStream.php new file mode 100644 index 00000000000..22ffc65f93b --- /dev/null +++ b/api/app/Console/Commands/MigratePoolStream.php @@ -0,0 +1,111 @@ +info('Updating job poster template work streams...'); + $jobPosterTemplatesUpdated = 0; + JobPosterTemplate::whereNotNull('stream')->chunkById(200, function (Collection $jobPosterTemplates) use ($workStreams, &$jobPosterTemplatesUpdated) { + foreach ($jobPosterTemplates as $jobPosterTemplate) { + $stream = $workStreams->where('key', $jobPosterTemplate->stream)->first(); + if ($stream) { + $jobPosterTemplate->work_stream_id = $stream->id; + $jobPosterTemplate->save(); + $jobPosterTemplatesUpdated++; + } else { + $this->error(sprintf('Work stream (%s) not found for job poster template (%s)', + $jobPosterTemplate->stream, + $jobPosterTemplate->id)); + } + } + }); + $this->info("Updated $jobPosterTemplatesUpdated job poster templates"); + + $this->newLine(); + $this->info('Updating pool work streams...'); + $poolsUpdated = 0; + Pool::whereNotNull('stream')->chunkById(200, function (Collection $pools) use ($workStreams, &$poolsUpdated) { + foreach ($pools as $pool) { + $stream = $workStreams->where('key', $pool->stream)->first(); + if ($stream) { + $pool->work_stream_id = $stream->id; + $pool->save(); + $poolsUpdated++; + } else { + $this->error(sprintf('Work stream (%s) not found for pool (%s)', + $pool->stream, + $pool->id)); + } + } + }); + $this->info("Updated $poolsUpdated pools"); + + $applicantFiltersUpdated = 0; + $this->newLine(); + $this->info('Updated applicant filter work streams...'); + ApplicantFilter::whereNotNull('qualified_streams')->chunkById(200, function (Collection $applicantFilters) use ($workStreams, &$applicantFiltersUpdated) { + foreach ($applicantFilters as $applicantFilter) { + $streams = $workStreams->whereIn('key', $applicantFilter->qualified_streams)->pluck('id'); + if ($streams->count()) { + $applicantFilter->workStreams()->sync($streams); + $applicantFiltersUpdated++; + } else { + $this->error(sprintf('Work streams (%s) not found for applicant filter (%s)', + implode(', ', $applicantFilter->qualified_streams), + $applicantFilter->id)); + } + } + }); + $this->info("Updated $applicantFiltersUpdated applicant filters"); + + $this->newLine(); + $this->info('Migration completed'); + $this->table(['Model', 'Affected'], [ + ['JobPosterTemplate', $jobPosterTemplatesUpdated], + ['Pool', $poolsUpdated], + ['ApplicantFilter', $applicantFiltersUpdated], + ]); + + } +} diff --git a/api/app/Console/Commands/SuspendPlacedCandidates.php b/api/app/Console/Commands/SuspendPlacedCandidates.php new file mode 100644 index 00000000000..4c01e87addb --- /dev/null +++ b/api/app/Console/Commands/SuspendPlacedCandidates.php @@ -0,0 +1,50 @@ +name, PoolCandidateStatus::PLACED_INDETERMINATE->name]; + + PoolCandidate::whereIn('pool_candidate_status', $applicableStatuses) + ->whereNull('suspended_at') + ->with('user') + ->chunkById(100, function (Collection $candidates) { + foreach ($candidates as $candidate) { + /** @var \App\Models\PoolCandidate $candidate */ + $candidate->suspended_at = Carbon::now(); + $candidate->save(); + } + } + ); + + return Command::SUCCESS; + } +} diff --git a/api/app/Enums/PoolCandidateStatus.php b/api/app/Enums/PoolCandidateStatus.php index 3140cfb378a..85e77b78761 100644 --- a/api/app/Enums/PoolCandidateStatus.php +++ b/api/app/Enums/PoolCandidateStatus.php @@ -28,12 +28,15 @@ enum PoolCandidateStatus case EXPIRED; case REMOVED; + // searchable candidates, so the available status and others treated as available for search purposes public static function qualifiedEquivalentGroup(): array { return [ PoolCandidateStatus::QUALIFIED_AVAILABLE->name, PoolCandidateStatus::PLACED_TENTATIVE->name, PoolCandidateStatus::PLACED_CASUAL->name, + PoolCandidateStatus::PLACED_TERM->name, + PoolCandidateStatus::PLACED_INDETERMINATE->name, ]; } diff --git a/api/app/GraphQL/Mutations/PlaceCandidate.php b/api/app/GraphQL/Mutations/PlaceCandidate.php index f5b3e62b769..f7797d260de 100644 --- a/api/app/GraphQL/Mutations/PlaceCandidate.php +++ b/api/app/GraphQL/Mutations/PlaceCandidate.php @@ -2,6 +2,7 @@ namespace App\GraphQL\Mutations; +use App\Enums\PlacementType; use App\Models\PoolCandidate; use Carbon\Carbon; @@ -25,6 +26,13 @@ public function __invoke($_, array $args) $candidate->computed_final_decision = $finalDecision['decision']; $candidate->computed_final_decision_weight = $finalDecision['weight']; + // If setting to term or indeterminate automatically suspend the candidate, otherwise null the field + if ($placementType === PlacementType::PLACED_TERM->name || $placementType === PlacementType::PLACED_INDETERMINATE->name) { + $candidate->suspended_at = $now; + } else { + $candidate->suspended_at = null; + } + $candidate->save(); return $candidate; diff --git a/api/app/GraphQL/Mutations/RevertPlaceCandidate.php b/api/app/GraphQL/Mutations/RevertPlaceCandidate.php index 9adfc1042ce..7dd869d14b7 100644 --- a/api/app/GraphQL/Mutations/RevertPlaceCandidate.php +++ b/api/app/GraphQL/Mutations/RevertPlaceCandidate.php @@ -17,6 +17,7 @@ public function __invoke($_, array $args) $candidate->pool_candidate_status = PoolCandidateStatus::QUALIFIED_AVAILABLE->name; $candidate->placed_at = null; $candidate->placed_department_id = null; + $candidate->suspended_at = null; $candidate->save(); diff --git a/api/app/GraphQL/Queries/CountPoolCandidatesByPool.php b/api/app/GraphQL/Queries/CountPoolCandidatesByPool.php index 3433f3a6aa5..cc5c65bbd72 100644 --- a/api/app/GraphQL/Queries/CountPoolCandidatesByPool.php +++ b/api/app/GraphQL/Queries/CountPoolCandidatesByPool.php @@ -28,12 +28,12 @@ public function __invoke($_, array $args) $query->whereClassifications($filters['qualifiedClassifications']); } - if (array_key_exists('qualifiedStreams', $filters)) { - $query->streams($filters['qualifiedStreams']); + if (array_key_exists('workStreams', $filters)) { + $query->whereWorkStreamsIn($filters['workStreams']); } }); - // available candidates scope (scope CANDIDATE_STATUS_QUALIFIED_AVAILABLE or CANDIDATE_STATUS_PLACED_CASUAL, or PLACED_TENTATIVE) + // available candidates scope (qualifiedEquivalentGroup, not expired, not suspended) PoolCandidate::scopeAvailable($queryBuilder); // Only display IT & OTHER publishing group candidates diff --git a/api/app/GraphQL/Validators/CreateUpdateWorkExperienceValidator.php b/api/app/GraphQL/Validators/CreateUpdateWorkExperienceValidator.php index a4fd70c1fcd..6f81e3c4eb5 100644 --- a/api/app/GraphQL/Validators/CreateUpdateWorkExperienceValidator.php +++ b/api/app/GraphQL/Validators/CreateUpdateWorkExperienceValidator.php @@ -4,6 +4,7 @@ use App\Enums\EmploymentCategory; use App\Enums\GovContractorType; +use App\Enums\GovPositionType; use App\Enums\WorkExperienceGovEmployeeType; use Illuminate\Validation\Rule; use Nuwave\Lighthouse\Validation\Validator; @@ -18,9 +19,10 @@ final class CreateUpdateWorkExperienceValidator extends Validator public function rules(): array { return [ - // 'workExperience.employmentCategory' => [ - // 'required', - // ], + 'workExperience.employmentCategory' => [ + 'sometimes', + 'required', + ], 'workExperience.extSizeOfOrganization' => [ Rule::requiredIf( ( @@ -60,7 +62,8 @@ public function rules(): array 'workExperience.govPositionType' => [ Rule::requiredIf( ( - $this->arg('workExperience.govEmploymentType') === WorkExperienceGovEmployeeType::INDETERMINATE->name + $this->arg('workExperience.govEmploymentType') === WorkExperienceGovEmployeeType::INDETERMINATE->name || + $this->arg('workExperience.govEmploymentType') === WorkExperienceGovEmployeeType::TERM->name ) ), Rule::prohibitedIf( @@ -68,6 +71,7 @@ public function rules(): array $this->arg('workExperience.employmentCategory') !== EmploymentCategory::GOVERNMENT_OF_CANADA->name ) ), + $this->arg('workExperience.govEmploymentType') === WorkExperienceGovEmployeeType::TERM->name ? Rule::notIn(GovPositionType::SUBSTANTIVE->name) : null, ], 'workExperience.govContractorRoleSeniority' => [ Rule::requiredIf( @@ -141,8 +145,10 @@ public function rules(): array ) ), ], - 'workExperience.classification' => [ + 'workExperience.classificationId' => [ Rule::requiredIf( + $this->arg('workExperience.employmentCategory') === EmploymentCategory::GOVERNMENT_OF_CANADA->name + && ( $this->arg('workExperience.govEmploymentType') === WorkExperienceGovEmployeeType::CASUAL->name ) || @@ -153,31 +159,15 @@ public function rules(): array $this->arg('workExperience.govEmploymentType') === WorkExperienceGovEmployeeType::INDETERMINATE->name ) ), - Rule::prohibitedIf( - ( - $this->arg('workExperience.employmentCategory') !== EmploymentCategory::GOVERNMENT_OF_CANADA->name - ) - ), - Rule::exists('classifications', 'id'), + // This does not work without proper connect/disconnect in the schema + // Rule::exists('classifications', 'id'), ], - 'workExperience.department' => [ + 'workExperience.departmentId' => [ Rule::requiredIf( - ( - $this->arg('workExperience.govEmploymentType') === WorkExperienceGovEmployeeType::CASUAL->name - ) || - ( - $this->arg('workExperience.govEmploymentType') === WorkExperienceGovEmployeeType::TERM->name - ) || - ( - $this->arg('workExperience.govEmploymentType') === WorkExperienceGovEmployeeType::INDETERMINATE->name - ) - ), - Rule::prohibitedIf( - ( - $this->arg('workExperience.employmentCategory') !== EmploymentCategory::GOVERNMENT_OF_CANADA->name - ) + $this->arg('workExperience.employmentCategory') === EmploymentCategory::GOVERNMENT_OF_CANADA->name ), - Rule::exists('departments', 'id'), + // This does not work without proper connect/disconnect in the schema + // Rule::exists('departments', 'id'), ], ]; } diff --git a/api/app/GraphQL/Validators/PoolIsCompleteValidator.php b/api/app/GraphQL/Validators/PoolIsCompleteValidator.php index dafedbcc457..ef6fd8f468c 100644 --- a/api/app/GraphQL/Validators/PoolIsCompleteValidator.php +++ b/api/app/GraphQL/Validators/PoolIsCompleteValidator.php @@ -30,7 +30,7 @@ public function rules(): array 'name.fr' => ['string'], 'classification_id' => ['required', 'uuid', 'exists:classifications,id'], 'department_id' => ['required', 'uuid', 'exists:departments,id'], - 'stream' => ['required', 'string'], + 'work_stream_id' => ['required', 'uuid', 'exists:work_streams,id'], 'opportunity_length' => ['required', 'string'], // Closing date diff --git a/api/app/Models/AssessmentStep.php b/api/app/Models/AssessmentStep.php index 799e6f3182a..8117cf845f5 100644 --- a/api/app/Models/AssessmentStep.php +++ b/api/app/Models/AssessmentStep.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Casts\LocalizedString; use App\Enums\AssessmentStepType; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; @@ -33,7 +34,7 @@ class AssessmentStep extends Model * The attributes that should be cast. */ protected $casts = [ - 'title' => 'array', + 'title' => LocalizedString::class, ]; /** diff --git a/api/app/Models/Classification.php b/api/app/Models/Classification.php index 9c93456ec4d..81067b806ef 100644 --- a/api/app/Models/Classification.php +++ b/api/app/Models/Classification.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Casts\LocalizedString; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; @@ -35,7 +36,7 @@ class Classification extends Model * The attributes that should be cast. */ protected $casts = [ - 'name' => 'array', + 'name' => LocalizedString::class, ]; /** @return HasMany */ diff --git a/api/app/Models/Community.php b/api/app/Models/Community.php index 45cc0220080..f5221d9afaf 100644 --- a/api/app/Models/Community.php +++ b/api/app/Models/Community.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Casts\LocalizedString; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany; @@ -26,9 +27,9 @@ class Community extends Model protected $keyType = 'string'; protected $casts = [ - 'name' => 'array', - 'description' => 'array', - 'mandate_authority' => 'array', + 'name' => LocalizedString::class, + 'description' => LocalizedString::class, + 'mandate_authority' => LocalizedString::class, ]; protected $fillable = [ diff --git a/api/app/Models/Department.php b/api/app/Models/Department.php index 809c49e1c6d..9c7a17dc721 100644 --- a/api/app/Models/Department.php +++ b/api/app/Models/Department.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Casts\LocalizedString; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; @@ -32,7 +33,7 @@ class Department extends Model * The attributes that should be case. */ protected $casts = [ - 'name' => 'array', + 'name' => LocalizedString::class, ]; /** @return HasMany */ diff --git a/api/app/Models/GeneralQuestion.php b/api/app/Models/GeneralQuestion.php index b09d79eb24e..4aa24d6b139 100644 --- a/api/app/Models/GeneralQuestion.php +++ b/api/app/Models/GeneralQuestion.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Casts\LocalizedString; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; @@ -30,7 +31,7 @@ class GeneralQuestion extends Model * The attributes that should be cast. */ protected $casts = [ - 'question' => 'array', + 'question' => LocalizedString::class, ]; /** diff --git a/api/app/Models/GenericJobTitle.php b/api/app/Models/GenericJobTitle.php index 2c91bdea3ed..b633a706269 100644 --- a/api/app/Models/GenericJobTitle.php +++ b/api/app/Models/GenericJobTitle.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Casts\LocalizedString; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; @@ -28,7 +29,7 @@ class GenericJobTitle extends Model * The attributes that should be cast. */ protected $casts = [ - 'name' => 'array', + 'name' => LocalizedString::class, ]; diff --git a/api/app/Models/JobPosterTemplate.php b/api/app/Models/JobPosterTemplate.php index ef459eea91e..e5357629bc4 100644 --- a/api/app/Models/JobPosterTemplate.php +++ b/api/app/Models/JobPosterTemplate.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Casts\LocalizedString; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; @@ -36,14 +37,14 @@ class JobPosterTemplate extends Model * The attributes that should be cast. */ protected $casts = [ - 'name' => 'array', - 'description' => 'array', - 'work_description' => 'array', - 'tasks' => 'array', - 'keywords' => 'array', - 'essential_technical_skills_notes' => 'array', - 'essential_behavioural_skills_notes' => 'array', - 'nonessential_technical_skills_notes' => 'array', + 'name' => LocalizedString::class, + 'description' => LocalizedString::class, + 'work_description' => LocalizedString::class, + 'tasks' => LocalizedString::class, + 'keywords' => LocalizedString::class, + 'essential_technical_skills_notes' => LocalizedString::class, + 'essential_behavioural_skills_notes' => LocalizedString::class, + 'nonessential_technical_skills_notes' => LocalizedString::class, ]; /** diff --git a/api/app/Models/Pool.php b/api/app/Models/Pool.php index 9925a842796..d15b6b1b4a8 100644 --- a/api/app/Models/Pool.php +++ b/api/app/Models/Pool.php @@ -3,6 +3,7 @@ namespace App\Models; use App\Builders\PoolBuilder; +use App\Casts\LocalizedString; use App\Enums\AssessmentStepType; use App\Enums\PoolSkillType; use App\Enums\PoolStatus; @@ -49,6 +50,7 @@ * @property string $team_id * @property string $department_id * @property string $community_id + * @property string $work_stream_id * @property ?string $area_of_selection * @property array $selection_limitations * @property \Illuminate\Support\Carbon $created_at @@ -70,15 +72,15 @@ class Pool extends Model * The attributes that should be cast. */ protected $casts = [ - 'name' => 'array', + 'name' => LocalizedString::class, 'operational_requirements' => 'array', - 'key_tasks' => 'array', - 'advertisement_location' => 'array', - 'your_impact' => 'array', - 'what_to_expect' => 'array', - 'special_note' => 'array', - 'what_to_expect_admission' => 'array', - 'about_us' => 'array', + 'key_tasks' => LocalizedString::class, + 'advertisement_location' => LocalizedString::class, + 'your_impact' => LocalizedString::class, + 'what_to_expect' => LocalizedString::class, + 'special_note' => LocalizedString::class, + 'what_to_expect_admission' => LocalizedString::class, + 'about_us' => LocalizedString::class, 'closing_date' => 'datetime', 'published_at' => 'datetime', 'is_remote' => 'boolean', @@ -130,6 +132,7 @@ class Pool extends Model 'department_id', 'community_id', 'area_of_selection', + 'work_stream_id', ]; /** diff --git a/api/app/Models/PoolCandidate.php b/api/app/Models/PoolCandidate.php index 477d46ca04b..2f95d9c3e38 100644 --- a/api/app/Models/PoolCandidate.php +++ b/api/app/Models/PoolCandidate.php @@ -48,7 +48,7 @@ * @property ?int $status_weight * @property string $pool_id * @property string $user_id - * @property ?\Illuminate\Support\Carbon $suspended_at + * @property ?\Carbon\Carbon $suspended_at * @property \Illuminate\Support\Carbon $created_at * @property ?\Illuminate\Support\Carbon $updated_at * @property array $submitted_steps @@ -310,7 +310,7 @@ public static function scopeQualifiedStreams(Builder $query, ?array $streams): B }) // Now scope for valid pools, according to streams ->whereHas('pool', function ($query) use ($streams) { - $query->whereIn('stream', $streams); + $query->whereWorkStreamsIn($streams); }); return $query; diff --git a/api/app/Models/PoolCandidateSearchRequest.php b/api/app/Models/PoolCandidateSearchRequest.php index a79bb0f06ae..f9215ae4939 100644 --- a/api/app/Models/PoolCandidateSearchRequest.php +++ b/api/app/Models/PoolCandidateSearchRequest.php @@ -146,18 +146,15 @@ public static function scopeSearchRequestStatus(Builder $query, ?array $searchRe return $query; } - public static function scopeStreams(Builder $query, ?array $streams): Builder + public static function scopeWorkStreams(Builder $query, ?array $streams): Builder { if (empty($streams)) { return $query; } - // streams is an array of PoolStream enums - $query->whereHas('applicantFilter', function ($query) use ($streams) { - $query->where(function ($query) use ($streams) { - foreach ($streams as $index => $stream) { - $query->orWhereJsonContains('qualified_streams', $stream); - } + $query->whereHas('applicantFilter', function ($filterQuery) use ($streams) { + $filterQuery->whereHas('workStreams', function ($workStreamQuery) use ($streams) { + $workStreamQuery->whereIn('applicant_filter_work_stream.work_stream_id', $streams); }); }); diff --git a/api/app/Models/Role.php b/api/app/Models/Role.php index 8b310f1cb85..b1c44accfba 100644 --- a/api/app/Models/Role.php +++ b/api/app/Models/Role.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Casts\LocalizedString; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\HasMany; use Laratrust\Models\Role as LaratrustRole; @@ -24,8 +25,8 @@ class Role extends LaratrustRole protected $keyType = 'string'; protected $casts = [ - 'display_name' => 'array', - 'description' => 'array', + 'display_name' => LocalizedString::class, + 'description' => LocalizedString::class, ]; protected $fillable = [ diff --git a/api/app/Models/ScreeningQuestion.php b/api/app/Models/ScreeningQuestion.php index 2f2b77b3829..b877e9e2d57 100644 --- a/api/app/Models/ScreeningQuestion.php +++ b/api/app/Models/ScreeningQuestion.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Casts\LocalizedString; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; @@ -31,7 +32,7 @@ class ScreeningQuestion extends Model * The attributes that should be cast. */ protected $casts = [ - 'question' => 'array', + 'question' => LocalizedString::class, ]; /** diff --git a/api/app/Models/Skill.php b/api/app/Models/Skill.php index 34a79d6a5ce..46ea9a9f818 100644 --- a/api/app/Models/Skill.php +++ b/api/app/Models/Skill.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Casts\LocalizedString; use App\Enums\PoolSkillType; use App\Enums\SkillCategory; use Illuminate\Database\Eloquent\Builder; @@ -36,8 +37,8 @@ class Skill extends Model * The attributes that should be cast. */ protected $casts = [ - 'name' => 'array', - 'description' => 'array', + 'name' => LocalizedString::class, + 'description' => LocalizedString::class, 'keywords' => 'array', ]; diff --git a/api/app/Models/SkillFamily.php b/api/app/Models/SkillFamily.php index 81adac8a8ea..99b8bc8d9ec 100644 --- a/api/app/Models/SkillFamily.php +++ b/api/app/Models/SkillFamily.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Casts\LocalizedString; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsToMany; @@ -28,8 +29,8 @@ class SkillFamily extends Model * The attributes that should be cast. */ protected $casts = [ - 'name' => 'array', - 'description' => 'array', + 'name' => LocalizedString::class, + 'description' => LocalizedString::class, ]; /** @return BelongsToMany */ diff --git a/api/app/Models/Team.php b/api/app/Models/Team.php index b0831fbdee8..dc9a740bd66 100644 --- a/api/app/Models/Team.php +++ b/api/app/Models/Team.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Casts\LocalizedString; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\BelongsToMany; @@ -27,8 +28,8 @@ class Team extends LaratrustTeam protected $keyType = 'string'; protected $casts = [ - 'display_name' => 'array', - 'description' => 'array', + 'display_name' => LocalizedString::class, + 'description' => LocalizedString::class, ]; protected $fillable = [ diff --git a/api/app/Models/TrainingOpportunity.php b/api/app/Models/TrainingOpportunity.php index f3c5a7904b2..1f4b3dbff3a 100644 --- a/api/app/Models/TrainingOpportunity.php +++ b/api/app/Models/TrainingOpportunity.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Casts\LocalizedString; use App\Enums\CourseLanguage; use App\Enums\DeadlineStatus; use Illuminate\Database\Eloquent\Builder; @@ -34,12 +35,12 @@ class TrainingOpportunity extends Model * The attributes that should be cast. */ protected $casts = [ - 'title' => 'array', + 'title' => LocalizedString::class, 'registration_deadline' => 'date', 'training_start' => 'date', 'training_end' => 'date', - 'description' => 'array', - 'application_url' => 'array', + 'description' => LocalizedString::class, + 'application_url' => LocalizedString::class, ]; /** diff --git a/api/app/Models/User.php b/api/app/Models/User.php index acce75e0aa5..078c5fd8fe8 100644 --- a/api/app/Models/User.php +++ b/api/app/Models/User.php @@ -779,7 +779,7 @@ public static function scopeTalentSearchablePublishingGroup(Builder $query, $arg } if (array_key_exists('qualifiedStreams', $filters)) { - $query->streams($filters['qualifiedStreams']); + $query->whereWorkStreamsIn($filters['qualifiedStreams']); } }); diff --git a/api/app/Models/WorkStream.php b/api/app/Models/WorkStream.php index 093a2b01c78..66608ee4e40 100644 --- a/api/app/Models/WorkStream.php +++ b/api/app/Models/WorkStream.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Casts\LocalizedString; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; @@ -24,8 +25,8 @@ class WorkStream extends Model protected $keyType = 'string'; protected $casts = [ - 'name' => 'array', - 'plain_language_name' => 'array', + 'name' => LocalizedString::class, + 'plain_language_name' => LocalizedString::class, ]; protected $fillable = [ diff --git a/api/app/Traits/Generator/GeneratesUserDoc.php b/api/app/Traits/Generator/GeneratesUserDoc.php index 27ea407a8c8..1c28ab22622 100644 --- a/api/app/Traits/Generator/GeneratesUserDoc.php +++ b/api/app/Traits/Generator/GeneratesUserDoc.php @@ -337,8 +337,7 @@ public function experience(Section $section, AwardExperience|CommunityExperience $this->localize('experiences.seniority_role'), $this->localizeEnum($experience->ext_role_seniority, ExternalRoleSeniority::class) ); - } - if ($experience->employment_category === EmploymentCategory::CANADIAN_ARMED_FORCES->name) { + } elseif ($experience->employment_category === EmploymentCategory::CANADIAN_ARMED_FORCES->name) { $section->addTitle( sprintf( '%s %s %s', @@ -361,8 +360,7 @@ public function experience(Section $section, AwardExperience|CommunityExperience $this->localize('experiences.rank_category'), $this->localizeEnum($experience->caf_rank, CafRank::class) ); - } - if ($experience->employment_category === EmploymentCategory::GOVERNMENT_OF_CANADA->name) { + } elseif ($experience->employment_category === EmploymentCategory::GOVERNMENT_OF_CANADA->name) { /** @var Department | null $department */ $department = Department::find($experience->department_id); $section->addTitle( @@ -424,6 +422,11 @@ public function experience(Section $section, AwardExperience|CommunityExperience $classification ? $classification->group.'-'.$classification->level : Lang::get('common.not_found', [], $this->lang), ); } + } else { + // null case, so experiences prior to adding employment_category + $section->addTitle($experience->getTitle($this->lang), $headingRank); + $section->addText($experience->getDateRange($this->lang)); + $this->addLabelText($section, $this->localize('experiences.team_group_division'), $experience->division); } } diff --git a/api/app/Traits/HasLocalization.php b/api/app/Traits/HasLocalization.php index 7eab6887bf8..11f13e4f5a9 100644 --- a/api/app/Traits/HasLocalization.php +++ b/api/app/Traits/HasLocalization.php @@ -24,6 +24,7 @@ public static function localizedString(string $value, ?string $parentKey = null) return [ 'en' => Lang::get($key, [], 'en'), 'fr' => Lang::get($key, [], 'fr'), + 'localized' => __($key), ]; } diff --git a/api/composer.lock b/api/composer.lock index e0d64ccc3cd..029a8105f55 100644 --- a/api/composer.lock +++ b/api/composer.lock @@ -2654,16 +2654,16 @@ }, { "name": "laravel/framework", - "version": "v11.35.0", + "version": "v11.36.1", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "f1a7aaa3c1235b7a95ccaa58db90e0cd9d8c3fcc" + "reference": "df06f5163f4550641fdf349ebc04916a61135a64" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/f1a7aaa3c1235b7a95ccaa58db90e0cd9d8c3fcc", - "reference": "f1a7aaa3c1235b7a95ccaa58db90e0cd9d8c3fcc", + "url": "https://api.github.com/repos/laravel/framework/zipball/df06f5163f4550641fdf349ebc04916a61135a64", + "reference": "df06f5163f4550641fdf349ebc04916a61135a64", "shasum": "" }, "require": { @@ -2684,7 +2684,7 @@ "guzzlehttp/uri-template": "^1.0", "laravel/prompts": "^0.1.18|^0.2.0|^0.3.0", "laravel/serializable-closure": "^1.3|^2.0", - "league/commonmark": "^2.2.1", + "league/commonmark": "^2.6", "league/flysystem": "^3.25.1", "league/flysystem-local": "^3.25.1", "league/uri": "^7.5.1", @@ -2699,7 +2699,7 @@ "symfony/console": "^7.0.3", "symfony/error-handler": "^7.0.3", "symfony/finder": "^7.0.3", - "symfony/http-foundation": "^7.0.3", + "symfony/http-foundation": "^7.2.0", "symfony/http-kernel": "^7.0.3", "symfony/mailer": "^7.0.3", "symfony/mime": "^7.0.3", @@ -2865,7 +2865,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-12-10T16:09:29+00:00" + "time": "2024-12-17T22:32:08+00:00" }, { "name": "laravel/prompts", @@ -3009,16 +3009,16 @@ }, { "name": "laravel/serializable-closure", - "version": "v2.0.0", + "version": "v2.0.1", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "0d8d3d8086984996df86596a86dea60398093a81" + "reference": "613b2d4998f85564d40497e05e89cb6d9bd1cbe8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/0d8d3d8086984996df86596a86dea60398093a81", - "reference": "0d8d3d8086984996df86596a86dea60398093a81", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/613b2d4998f85564d40497e05e89cb6d9bd1cbe8", + "reference": "613b2d4998f85564d40497e05e89cb6d9bd1cbe8", "shasum": "" }, "require": { @@ -3066,7 +3066,7 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2024-11-19T01:38:44+00:00" + "time": "2024-12-16T15:26:28+00:00" }, { "name": "laravel/tinker", @@ -6206,16 +6206,16 @@ }, { "name": "spatie/laravel-package-tools", - "version": "1.16.6", + "version": "1.17.0", "source": { "type": "git", "url": "https://github.com/spatie/laravel-package-tools.git", - "reference": "1f26942dc1e5c49eacfced34fdbc29ed234bd7b3" + "reference": "9ab30fd24f677e5aa370ea4cf6b41c517d16cf85" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/1f26942dc1e5c49eacfced34fdbc29ed234bd7b3", - "reference": "1f26942dc1e5c49eacfced34fdbc29ed234bd7b3", + "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/9ab30fd24f677e5aa370ea4cf6b41c517d16cf85", + "reference": "9ab30fd24f677e5aa370ea4cf6b41c517d16cf85", "shasum": "" }, "require": { @@ -6224,10 +6224,10 @@ }, "require-dev": { "mockery/mockery": "^1.5", - "orchestra/testbench": "^7.7|^8.0", - "pestphp/pest": "^1.22", - "phpunit/phpunit": "^9.5.24", - "spatie/pest-plugin-test-time": "^1.1" + "orchestra/testbench": "^7.7|^8.0|^9.0", + "pestphp/pest": "^1.22|^2", + "phpunit/phpunit": "^9.5.24|^10.5", + "spatie/pest-plugin-test-time": "^1.1|^2.2" }, "type": "library", "autoload": { @@ -6254,7 +6254,7 @@ ], "support": { "issues": "https://github.com/spatie/laravel-package-tools/issues", - "source": "https://github.com/spatie/laravel-package-tools/tree/1.16.6" + "source": "https://github.com/spatie/laravel-package-tools/tree/1.17.0" }, "funding": [ { @@ -6262,20 +6262,20 @@ "type": "github" } ], - "time": "2024-11-18T15:02:02+00:00" + "time": "2024-12-09T16:29:14+00:00" }, { "name": "spatie/php-structure-discoverer", - "version": "2.2.0", + "version": "2.2.1", "source": { "type": "git", "url": "https://github.com/spatie/php-structure-discoverer.git", - "reference": "271542206169d95dd2ffe346ddf11f37672553a2" + "reference": "e2b39ba0baaf05d1300c5467e7ee8a6439324827" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/php-structure-discoverer/zipball/271542206169d95dd2ffe346ddf11f37672553a2", - "reference": "271542206169d95dd2ffe346ddf11f37672553a2", + "url": "https://api.github.com/repos/spatie/php-structure-discoverer/zipball/e2b39ba0baaf05d1300c5467e7ee8a6439324827", + "reference": "e2b39ba0baaf05d1300c5467e7ee8a6439324827", "shasum": "" }, "require": { @@ -6334,7 +6334,7 @@ ], "support": { "issues": "https://github.com/spatie/php-structure-discoverer/issues", - "source": "https://github.com/spatie/php-structure-discoverer/tree/2.2.0" + "source": "https://github.com/spatie/php-structure-discoverer/tree/2.2.1" }, "funding": [ { @@ -6342,7 +6342,7 @@ "type": "github" } ], - "time": "2024-08-29T10:43:45+00:00" + "time": "2024-12-16T13:29:18+00:00" }, { "name": "spatie/regex", @@ -11773,13 +11773,13 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": [], "prefer-stable": true, "prefer-lowest": false, "platform": { "php": "^8.3" }, - "platform-dev": {}, + "platform-dev": [], "platform-overrides": { "php": "8.3.9" }, diff --git a/api/database/factories/ApplicantFilterFactory.php b/api/database/factories/ApplicantFilterFactory.php index 645b4b3d231..05382731833 100644 --- a/api/database/factories/ApplicantFilterFactory.php +++ b/api/database/factories/ApplicantFilterFactory.php @@ -4,7 +4,6 @@ use App\Enums\LanguageAbility; use App\Enums\OperationalRequirement; -use App\Enums\PoolStream; use App\Enums\PositionDuration; use App\Enums\WorkRegion; use App\Models\ApplicantFilter; @@ -95,21 +94,35 @@ public function withRelationships(bool $sparse = false) )->get(); $filter->pools()->saveMany($pools); $filter->qualifiedClassifications()->saveMany($pools->flatMap(fn ($pool) => $pool->classification)); - $stream = (empty($pools) || count($pools) === 0) ? $this->faker->randomElements( - array_column(PoolStream::cases(), 'name'), - ) : [$pools[0]->stream]; + $streams = $pools->map(fn ($pool) => $pool->workStream); + $filter->workStreams()->saveMany($streams); $ATIP = Community::where('key', 'atip')->first(); $digital = Community::where('key', 'digital')->first(); - if (in_array(PoolStream::ACCESS_INFORMATION_PRIVACY->name, $stream) && $ATIP?->id) { + $isATIP = $streams->contains(fn ($stream) => $stream->key === 'ACCESS_INFORMATION_PRIVACY'); + + if ($isATIP && $ATIP?->id) { $filter->community_id = $ATIP->id; } elseif ($digital?->id) { $filter->community_id = $digital->id; } - $filter->qualified_streams = $stream; $filter->save(); }); } + + /** + * Create an ApplicantFilter with specific work streams + * + * @var \Illuminate\Support\Collection + * + * @return \Illuminate\Database\Eloquent\Factories\Factory + */ + public function withWorkStreams(array $workStreams) + { + return $this->afterCreating(function (ApplicantFilter $filter) use ($workStreams) { + $filter->workStreams()->saveMany($workStreams); + }); + } } diff --git a/api/database/factories/PoolFactory.php b/api/database/factories/PoolFactory.php index 679d02436ad..c6a446861f2 100644 --- a/api/database/factories/PoolFactory.php +++ b/api/database/factories/PoolFactory.php @@ -188,9 +188,9 @@ public function draft(): Factory // the base state is draft already $hasSpecialNote = $this->faker->boolean(); $isRemote = $this->faker->boolean(); - $workStreamId = WorkStream::inRandomOrder()->first()?->id; - if (! $workStreamId) { - $workStreamId = WorkStream::factory()->create()->id; + $workStream = WorkStream::inRandomOrder()->first(); + if (! $workStream) { + $workStream = WorkStream::factory()->create(); } return [ @@ -207,7 +207,7 @@ public function draft(): Factory 'special_note' => ! $hasSpecialNote ? ['en' => $this->faker->paragraph().' EN', 'fr' => $this->faker->paragraph().' FR'] : null, 'is_remote' => $this->faker->boolean, 'stream' => $this->faker->randomElement(PoolStream::cases())->name, - 'work_stream_id' => $workStreamId, + 'work_stream_id' => $workStream->id, 'process_number' => $this->faker->word(), 'publishing_group' => $this->faker->randomElement(array_column(PublishingGroup::cases(), 'name')), 'opportunity_length' => $this->faker->randomElement(array_column(PoolOpportunityLength::cases(), 'name')), diff --git a/api/graphql/schema.graphql b/api/graphql/schema.graphql index 2084f9de921..e1b89f38782 100644 --- a/api/graphql/schema.graphql +++ b/api/graphql/schema.graphql @@ -23,6 +23,7 @@ scalar UUID @scalar(class: "UUID") type LocalizedString { en: String fr: String + localized: String } type LocalizedEnumString { @@ -277,7 +278,7 @@ type Pool implements HasRoleAssignments { @rename(attribute: "security_clearance") language: LocalizedPoolLanguage @rename(attribute: "advertisement_language") status: LocalizedPoolStatus @rename(attribute: "status") - stream: LocalizedPoolStream + workStream: WorkStream @belongsTo processNumber: String @rename(attribute: "process_number") publishingGroup: LocalizedPublishingGroup @rename(attribute: "publishing_group") @@ -589,8 +590,7 @@ type ApplicantFilter { skills: [Skill] @belongsToMany # request creation connects to qualifiedClassifications qualifiedClassifications: [Classification] @belongsToMany # Filters applicants based on the classifications pools they've qualified in. - qualifiedStreams: [LocalizedPoolStream] - @rename(attribute: "qualified_streams") # Filters applicants based on the streams of the pools they've qualified in. + workStreams: [WorkStream!] @belongsToMany # Filters applicants based on the streams of the pools they've qualified in. pools: [Pool] @belongsToMany @canResolved(ability: "view") community: Community @belongsTo # Currently does not affect search, scope needs to be added } @@ -780,7 +780,6 @@ type JobPosterTemplate { description: LocalizedString supervisoryStatus: LocalizedSupervisoryStatus @rename(attribute: "supervisory_status") - stream: LocalizedPoolStream workDescription: LocalizedString @rename(attribute: "work_description") tasks: LocalizedString keywords: LocalizedKeywords @@ -792,6 +791,7 @@ type JobPosterTemplate { @rename(attribute: "nonessential_technical_skills_notes") classification: Classification @belongsTo + workStream: WorkStream @belongsTo skills: [JobPosterTemplateSkill!] @belongsToMany(model: "Skill") } @@ -853,7 +853,7 @@ input PoolFilterInput { generalSearch: String @scope name: String @scope team: String @scope - streams: [PoolStream!] @scope + workStreams: [UUID!] @scope(name: "whereWorkStreamsIn") statuses: [PoolStatus!] = [] @scope processNumber: String @scope publishingGroups: [PublishingGroup!] @scope @@ -867,6 +867,11 @@ input PoolTeamDisplayNameOrderByInput { order: SortOrder! } +input PoolWorkStreamNameOrderByInput { + locale: String! + order: SortOrder! +} + input PoolBookmarksOrderByInput { column: String! order: SortOrder! @@ -892,7 +897,7 @@ input ApplicantFilterInput { skillsIntersectional: [IdInput] @scope @pluck(key: "id") # AND filtering skills as opposed to OR qualifiedClassifications: [ClassificationFilterInput] @scope(name: "qualifiedClassifications") # Filters applicants based on the classification of pools they are currently qualified and available in. - qualifiedStreams: [PoolStream] @scope(name: "qualifiedStreams") # Filters applicants based on the stream of pools they are currently qualified and available in. + workStreams: [IdInput] @scope(name: "qualifiedStreams") # Filters applicants based on the stream of pools they are currently qualified and available in. community: IdInput @scope(name: "candidatesInCommunity") @pluck(key: "id") } @@ -920,7 +925,7 @@ input PoolCandidateSearchRequestInput { status: [PoolCandidateSearchStatus] @scope(name: "searchRequestStatus") departments: [ID] @scope classifications: [ID] @scope - streams: [PoolStream] @scope + workStreams: [UUID] @scope fullName: String @scope email: String @scope id: ID @scope @@ -1026,6 +1031,7 @@ type Query { where: PoolFilterInput orderByPoolBookmarks: PoolBookmarksOrderByInput @scope orderByTeamDisplayName: PoolTeamDisplayNameOrderByInput @scope + orderByWorkStreamName: PoolWorkStreamNameOrderByInput @scope orderByColumn: OrderByColumnInput @scope orderBy: _ @orderBy( @@ -1583,7 +1589,7 @@ input CreateApplicantFilterInput { citizenship: CitizenshipStatus armedForcesStatus: ArmedForcesStatus @rename(attribute: "armed_forces_status") qualifiedClassifications: ClassificationBelongsToMany - qualifiedStreams: [PoolStream] @rename(attribute: "qualified_streams") + workStreams: WorkStreamBelongsToMany community: CommunityBelongsTo } @@ -1694,12 +1700,8 @@ input WorkExperienceInput { @rename(attribute: "contractor_firm_agency_name") cafForce: CafForce @rename(attribute: "caf_force") cafRank: CafRank @rename(attribute: "caf_rank") - classification: ClassificationBelongsTo - @pluck(key: "connect") - @rename(attribute: "classification_id") - department: DepartmentBelongsTo - @pluck(key: "connect") - @rename(attribute: "department_id") + classificationId: String @rename(attribute: "classification_id") + departmentId: String @rename(attribute: "department_id") } input PersonalExperienceInput { title: String @@ -1831,7 +1833,7 @@ input UpdatePoolInput { name: LocalizedStringInput classification: ClassificationBelongsTo department: DepartmentBelongsTo - stream: PoolStream + workStream: WorkStreamBelongsTo processNumber: String @rename(attribute: "process_number") # Closing date closingDate: DateTime @@ -2084,6 +2086,7 @@ input CreateJobPosterTemplateInput @validator { description: LocalizedStringInput! supervisoryStatus: SupervisoryStatus! @rename(attribute: "supervisory_status") stream: PoolStream! + workStream: WorkStreamBelongsTo! workDescription: LocalizedStringInput @rename(attribute: "work_description") tasks: LocalizedStringInput! keywords: LocalizedKeywordsInput @@ -2103,7 +2106,7 @@ input UpdateJobPosterTemplateInput @validator { name: LocalizedStringInput description: LocalizedStringInput supervisoryStatus: SupervisoryStatus @rename(attribute: "supervisory_status") - stream: PoolStream + workStream: WorkStreamBelongsTo workDescription: LocalizedStringInput @rename(attribute: "work_description") tasks: LocalizedStringInput keywords: LocalizedStringInput diff --git a/api/storage/app/lighthouse-schema.graphql b/api/storage/app/lighthouse-schema.graphql index 351b417b9ac..c7d8660d4e0 100755 --- a/api/storage/app/lighthouse-schema.graphql +++ b/api/storage/app/lighthouse-schema.graphql @@ -346,6 +346,7 @@ type Query { where: PoolFilterInput orderByPoolBookmarks: PoolBookmarksOrderByInput orderByTeamDisplayName: PoolTeamDisplayNameOrderByInput + orderByWorkStreamName: PoolWorkStreamNameOrderByInput orderByColumn: OrderByColumnInput orderBy: [QueryPoolsPaginatedOrderByRelationOrderByClause!] @@ -540,6 +541,7 @@ scalar UUID type LocalizedString { en: String fr: String + localized: String } type LocalizedEnumString { @@ -737,7 +739,7 @@ type Pool implements HasRoleAssignments { securityClearance: LocalizedSecurityStatus language: LocalizedPoolLanguage status: LocalizedPoolStatus - stream: LocalizedPoolStream + workStream: WorkStream processNumber: String publishingGroup: LocalizedPublishingGroup opportunityLength: LocalizedPoolOpportunityLength @@ -972,7 +974,7 @@ type ApplicantFilter { positionDuration: [PositionDuration] skills: [Skill] qualifiedClassifications: [Classification] - qualifiedStreams: [LocalizedPoolStream] + workStreams: [WorkStream!] pools: [Pool] community: Community } @@ -1136,7 +1138,6 @@ type JobPosterTemplate { name: LocalizedString description: LocalizedString supervisoryStatus: LocalizedSupervisoryStatus - stream: LocalizedPoolStream workDescription: LocalizedString tasks: LocalizedString keywords: LocalizedKeywords @@ -1144,6 +1145,7 @@ type JobPosterTemplate { essentialBehaviouralSkillsNotes: LocalizedString nonessentialTechnicalSkillsNotes: LocalizedString classification: Classification + workStream: WorkStream skills: [JobPosterTemplateSkill!] } @@ -1205,7 +1207,7 @@ input PoolFilterInput { generalSearch: String name: String team: String - streams: [PoolStream!] + workStreams: [UUID!] statuses: [PoolStatus!] = [] processNumber: String publishingGroups: [PublishingGroup!] @@ -1218,6 +1220,11 @@ input PoolTeamDisplayNameOrderByInput { order: SortOrder! } +input PoolWorkStreamNameOrderByInput { + locale: String! + order: SortOrder! +} + input PoolBookmarksOrderByInput { column: String! order: SortOrder! @@ -1240,7 +1247,7 @@ input ApplicantFilterInput { skills: [IdInput] skillsIntersectional: [IdInput] qualifiedClassifications: [ClassificationFilterInput] - qualifiedStreams: [PoolStream] + workStreams: [IdInput] community: IdInput } @@ -1264,7 +1271,7 @@ input PoolCandidateSearchRequestInput { status: [PoolCandidateSearchStatus] departments: [ID] classifications: [ID] - streams: [PoolStream] + workStreams: [UUID] fullName: String email: String id: ID @@ -1640,7 +1647,7 @@ input CreateApplicantFilterInput { citizenship: CitizenshipStatus armedForcesStatus: ArmedForcesStatus qualifiedClassifications: ClassificationBelongsToMany - qualifiedStreams: [PoolStream] + workStreams: WorkStreamBelongsToMany community: CommunityBelongsTo } @@ -1735,8 +1742,8 @@ input WorkExperienceInput { contractorFirmAgencyName: String cafForce: CafForce cafRank: CafRank - classification: ClassificationBelongsTo - department: DepartmentBelongsTo + classificationId: String + departmentId: String } input PersonalExperienceInput { @@ -1869,7 +1876,7 @@ input UpdatePoolInput { name: LocalizedStringInput classification: ClassificationBelongsTo department: DepartmentBelongsTo - stream: PoolStream + workStream: WorkStreamBelongsTo processNumber: String closingDate: DateTime closingReason: String @@ -2080,6 +2087,7 @@ input CreateJobPosterTemplateInput { description: LocalizedStringInput! supervisoryStatus: SupervisoryStatus! stream: PoolStream! + workStream: WorkStreamBelongsTo! workDescription: LocalizedStringInput tasks: LocalizedStringInput! keywords: LocalizedKeywordsInput @@ -2096,7 +2104,7 @@ input UpdateJobPosterTemplateInput { name: LocalizedStringInput description: LocalizedStringInput supervisoryStatus: SupervisoryStatus - stream: PoolStream + workStream: WorkStreamBelongsTo workDescription: LocalizedStringInput tasks: LocalizedStringInput keywords: LocalizedStringInput diff --git a/api/tests/Feature/ApplicantFilterTest.php b/api/tests/Feature/ApplicantFilterTest.php index 4a6d8663900..767c2528f06 100644 --- a/api/tests/Feature/ApplicantFilterTest.php +++ b/api/tests/Feature/ApplicantFilterTest.php @@ -4,7 +4,6 @@ use App\Enums\LanguageAbility; use App\Enums\PoolCandidateSearchStatus; -use App\Enums\PoolStream; use App\Facades\Notify; use App\Models\ApplicantFilter; use App\Models\Community; @@ -83,13 +82,13 @@ protected function filterToInput(ApplicantFilter $filter) 'positionDuration' => $filter->position_duration, 'skills' => $filter->skills->map($onlyId)->toArray(), 'pools' => $filter->pools->map($onlyId)->toArray(), + 'workStreams' => $filter->workStreams->map($onlyId)->toArray(), 'qualifiedClassifications' => $filter->qualifiedClassifications->map(function ($classification) { return [ 'group' => $classification->group, 'level' => $classification->level, ]; })->toArray(), - 'qualifiedStreams' => $filter->qualified_streams, 'community' => ['id' => $filter->community->id], ]; } @@ -103,6 +102,9 @@ protected function filterToCreateInput(ApplicantFilter $filter) $input['pools'] = [ 'sync' => $filter->pools->pluck('id')->toArray(), ]; + $input['workStreams'] = [ + 'sync' => $filter->workStreams->pluck('id')->toArray(), + ]; $input['qualifiedClassifications'] = [ 'sync' => $filter->qualifiedClassifications->pluck('id')->toArray(), ]; @@ -273,6 +275,7 @@ public function testQueryRelationships() name { en fr + localized } } pools { @@ -280,14 +283,16 @@ public function testQueryRelationships() name { en fr + localized } } - qualifiedStreams { value } + workStreams { id } qualifiedClassifications { id name { en fr + localized } } community { @@ -306,7 +311,7 @@ public function testQueryRelationships() $this->assertCount($filter->qualifiedClassifications->count(), $retrievedFilter['qualifiedClassifications']); $this->assertCount($filter->skills->count(), $retrievedFilter['skills']); $this->assertCount($filter->pools->count(), $retrievedFilter['pools']); - $this->assertCount(count($filter->qualified_streams), $retrievedFilter['qualifiedStreams']); + $this->assertCount($filter->workStreams->count(), $retrievedFilter['workStreams']); // Assert that all the content in each collection is correct. foreach ($filter->pools as $pool) { @@ -322,9 +327,11 @@ public function testQueryRelationships() $response->assertJsonFragment(['id' => $skill->id, 'name' => $skill->name]); } - $response->assertJsonFragment(['qualifiedStreams' => [[ - 'value' => $filter->qualified_streams[0], - ]]]); + foreach ($filter->workStreams as $workStream) { + $response->assertJsonFragment([ + 'id' => $workStream->id, + ]); + } $response->assertJsonFragment(['community' => ['id' => $filter->community_id]]); } @@ -434,7 +441,6 @@ public function testFilterCanBeStoredAndRetrievedWithoutChangingResults() 'en' => 'Test Pool EN', 'fr' => 'Test Pool FR', ], - 'stream' => PoolStream::BUSINESS_ADVISORY_SERVICES->name, 'community_id' => $community->id, ]); // Create candidates who may show up in searches @@ -475,7 +481,7 @@ public function testFilterCanBeStoredAndRetrievedWithoutChangingResults() $candidateSkills = $candidateUser->experiences[0]->skills; $filter->skills()->saveMany($candidateSkills->shuffle()->take(3)); $filter->pools()->save($pool); - $filter->qualified_streams = $pool->stream; + $filter->workStreams()->saveMany([$pool->workStream]); $filter->save(); $response = $this->graphQL( /** @lang GraphQL */ @@ -547,7 +553,7 @@ public function testFilterCanBeStoredAndRetrievedWithoutChangingResults() locationPreferences { value } operationalRequirements { value } positionDuration - qualifiedStreams { value } + workStreams { id } qualifiedClassifications { group level @@ -573,7 +579,6 @@ public function testFilterCanBeStoredAndRetrievedWithoutChangingResults() $retrievedFilter['locationPreferences'] = $this->filterEnumToInput($retrievedFilter, 'locationPreferences'); $retrievedFilter['operationalRequirements'] = $this->filterEnumToInput($retrievedFilter, 'operationalRequirements'); - $retrievedFilter['qualifiedStreams'] = $this->filterEnumToInput($retrievedFilter, 'qualifiedStreams'); // Now use the retrieved filter to get the same count $response = $this->graphQL( diff --git a/api/tests/Feature/ApplicantTest.php b/api/tests/Feature/ApplicantTest.php index d6464888513..6c570118bdf 100644 --- a/api/tests/Feature/ApplicantTest.php +++ b/api/tests/Feature/ApplicantTest.php @@ -8,7 +8,6 @@ use App\Enums\LanguageAbility; use App\Enums\OperationalRequirement; use App\Enums\PoolCandidateStatus; -use App\Enums\PoolStream; use App\Enums\PositionDuration; use App\Enums\PublishingGroup; use App\Facades\Notify; @@ -21,6 +20,7 @@ use App\Models\Skill; use App\Models\User; use App\Models\WorkExperience; +use App\Models\WorkStream; use Database\Seeders\RolePermissionSeeder; use Illuminate\Foundation\Testing\RefreshDatabase; use Nuwave\Lighthouse\Testing\MakesGraphQLRequests; @@ -1922,24 +1922,24 @@ public function testClassificationAndStreamsFilter() $targetClassification = Classification::factory()->create(); $excludedClassification = Classification::factory()->create(); - $targetStream = PoolStream::BUSINESS_ADVISORY_SERVICES->name; - $excludedStream = PoolStream::ACCESS_INFORMATION_PRIVACY->name; + $targetStream = WorkStream::factory()->create(); + $excludedStream = WorkStream::factory()->create(); $targetClassificationPool = Pool::factory()->candidatesAvailableInSearch()->create([ 'classification_id' => $targetClassification, - 'stream' => $excludedStream, + 'work_stream_id' => $excludedStream->id, ]); $targetStreamPool = Pool::factory()->candidatesAvailableInSearch()->create([ 'classification_id' => $excludedClassification, - 'stream' => $targetStream, + 'work_stream_id' => $targetStream->id, ]); $targetStreamAndClassificationPool = Pool::factory()->candidatesAvailableInSearch()->create([ 'classification_id' => $targetClassification, - 'stream' => $targetStream, + 'work_stream_id' => $targetStream->id, ]); $excludedPool = Pool::factory()->candidatesAvailableInSearch()->create([ 'classification_id' => $excludedClassification, - 'stream' => $excludedStream, + 'work_stream_id' => $excludedStream->id, ]); $targetUser = User::factory()->create(); @@ -2017,7 +2017,7 @@ public function testClassificationAndStreamsFilter() ->graphQL($query, [ 'where' => [ - 'qualifiedStreams' => [$targetStream], + 'workStreams' => [['id' => $targetStream->id]], ], ] )->assertJson([ @@ -2036,9 +2036,9 @@ public function testClassificationAndStreamsFilter() 'level' => $targetClassification->level, ], ], - 'qualifiedStreams' => [ - $targetStream, - ], + 'workStreams' => [[ + 'id' => $targetStream->id, + ]], ], ] )->assertJson([ diff --git a/api/tests/Feature/CommunityTest.php b/api/tests/Feature/CommunityTest.php index bd892884644..ea828be181f 100644 --- a/api/tests/Feature/CommunityTest.php +++ b/api/tests/Feature/CommunityTest.php @@ -47,11 +47,10 @@ protected function setUp(): void // Create communities. $this->toBeDeletedUUID = $this->faker->UUID(); - $this->community1 = Community::factory()->create(['name' => 'community1']); - $this->community2 = Community::factory()->create(['name' => 'community2']); + $this->community1 = Community::factory()->create(); + $this->community2 = Community::factory()->create(); $this->community3 = Community::factory()->create([ 'id' => $this->toBeDeletedUUID, // need specific ID for delete community testing. - 'name' => 'community3', ]); // Create users. diff --git a/api/tests/Feature/CountPoolCandidatesByPoolTest.php b/api/tests/Feature/CountPoolCandidatesByPoolTest.php index 0566e8175bd..fdd72b71507 100644 --- a/api/tests/Feature/CountPoolCandidatesByPoolTest.php +++ b/api/tests/Feature/CountPoolCandidatesByPoolTest.php @@ -5,7 +5,6 @@ use App\Enums\LanguageAbility; use App\Enums\OperationalRequirement; use App\Enums\PoolCandidateStatus; -use App\Enums\PoolStream; use App\Enums\PositionDuration; use App\Enums\PublishingGroup; use App\Enums\WorkRegion; @@ -16,6 +15,7 @@ use App\Models\PoolCandidate; use App\Models\Skill; use App\Models\User; +use App\Models\WorkStream; use Database\Seeders\RolePermissionSeeder; use Illuminate\Foundation\Testing\RefreshDatabase; use Nuwave\Lighthouse\Testing\MakesGraphQLRequests; @@ -771,9 +771,21 @@ public function testAdditionalAvailabilityScopes() 'group' => 'IT', 'level' => 1, ]); + + $unaccosiatedStream = WorkStream::factory()->create(); + $unaccosiatedPool = Pool::factory()->candidatesAvailableInSearch()->published()->create([ + 'work_stream_id' => $unaccosiatedStream->id, + ]); + PoolCandidate::factory()->create([ + 'pool_id' => $unaccosiatedPool->id, + 'pool_candidate_status' => PoolCandidateStatus::QUALIFIED_AVAILABLE->name, + 'expiry_date' => config('constants.far_future_date'), + ]); + + $stream = WorkStream::factory()->create(); $pool = Pool::factory()->candidatesAvailableInSearch()->create([ 'published_at' => config('constants.past_date'), - 'stream' => PoolStream::ACCESS_INFORMATION_PRIVACY->name, + 'work_stream_id' => $stream->id, ]); $user1 = User::factory()->create(); PoolCandidate::factory()->create([ @@ -802,7 +814,7 @@ public function testAdditionalAvailabilityScopes() 'level' => 1, ], ], - 'qualifiedStreams' => [PoolStream::ACCESS_INFORMATION_PRIVACY->name], + 'workStreams' => [['id' => $stream->id]], ], ] )->assertSimilarJson([ @@ -816,4 +828,58 @@ public function testAdditionalAvailabilityScopes() ], ]); } + + // asserts placed term/indeterminate candidates can appear in this query, can't check by id though so check that 2 out of 3 appear + public function testPlacedSuspendedNotSuspendedCandidates() + { + $itPool = Pool::factory()->create([ + ...$this->poolData(), + 'publishing_group' => PublishingGroup::IT_JOBS->name, + ]); + PoolCandidate::truncate(); + PoolCandidate::factory()->availableInSearch()->create([ + 'pool_id' => $itPool, + 'pool_candidate_status' => PoolCandidateStatus::PLACED_TERM->name, + 'suspended_at' => null, + ]); + PoolCandidate::factory()->availableInSearch()->create([ + 'pool_id' => $itPool, + 'pool_candidate_status' => PoolCandidateStatus::PLACED_INDETERMINATE->name, + 'suspended_at' => null, + ]); + PoolCandidate::factory()->availableInSearch()->create([ + 'pool_id' => $itPool, + 'pool_candidate_status' => PoolCandidateStatus::PLACED_TERM->name, + 'suspended_at' => config('constants.far_past_datetime'), + ]); + + // expect 2, the 2 un-suspended ones + $this->graphQL( + /** @lang GraphQL */ + ' + query ($where: ApplicantFilterInput) { + countPoolCandidatesByPool(where: $where) { + pool { id } + candidateCount + } + } + ', + [ + 'where' => [ + 'pools' => [ + ['id' => $itPool->id], + ], + ], + ] + )->assertSimilarJson([ + 'data' => [ + 'countPoolCandidatesByPool' => [ + [ + 'pool' => ['id' => $itPool->id], + 'candidateCount' => 2, + ], + ], + ], + ]); + } } diff --git a/api/tests/Feature/JobPosterTemplateTest.php b/api/tests/Feature/JobPosterTemplateTest.php index b41223dfb3a..e53c140de68 100644 --- a/api/tests/Feature/JobPosterTemplateTest.php +++ b/api/tests/Feature/JobPosterTemplateTest.php @@ -13,6 +13,7 @@ use Database\Seeders\SkillSeeder; use Database\Seeders\WorkStreamSeeder; use Illuminate\Foundation\Testing\RefreshDatabase; +use Illuminate\Support\Arr; use Nuwave\Lighthouse\Testing\MakesGraphQLRequests; use Nuwave\Lighthouse\Testing\RefreshesSchemaCache; use Tests\TestCase; @@ -301,19 +302,22 @@ private function getCreateInput(): array return [ 'referenceId' => $template->reference_id, - 'name' => $template->name, - 'description' => $template->description, + 'name' => Arr::only($template->name, ['en', 'fr']), + 'description' => Arr::only($template->description, ['en', 'fr']), 'supervisoryStatus' => $template->supervisory_status, 'stream' => $template->stream, - 'tasks' => $template->tasks, - 'workDescription' => $template->work_description, - 'keywords' => $template->keywords, - 'essentialBehaviouralSkillsNotes' => $template->essential_behavioural_skills_notes, - 'essentialTechnicalSkillsNotes' => $template->essential_technical_skills_notes, - 'nonessentialTechnicalSkillsNotes' => $template->nonessential_technical_skills_notes, + 'tasks' => Arr::only($template->tasks, ['en', 'fr']), + 'workDescription' => Arr::only($template->work_description, ['en', 'fr']), + 'keywords' => Arr::only($template->keywords, ['en', 'fr']), + 'essentialBehaviouralSkillsNotes' => Arr::only($template->essential_behavioural_skills_notes, ['en', 'fr']), + 'essentialTechnicalSkillsNotes' => Arr::only($template->essential_technical_skills_notes, ['en', 'fr']), + 'nonessentialTechnicalSkillsNotes' => Arr::only($template->nonessential_technical_skills_notes, ['en', 'fr']), 'classification' => [ 'connect' => $template->classification->id, ], + 'workStream' => [ + 'connect' => $template->workStream->id, + ], 'skills' => [ 'connect' => $template->skills->map(function ($skill) { return [ diff --git a/api/tests/Feature/PoolCandidateSearchRequestPaginatedTest.php b/api/tests/Feature/PoolCandidateSearchRequestPaginatedTest.php index 060e9571ee3..074695f78d1 100644 --- a/api/tests/Feature/PoolCandidateSearchRequestPaginatedTest.php +++ b/api/tests/Feature/PoolCandidateSearchRequestPaginatedTest.php @@ -3,13 +3,13 @@ namespace Tests\Feature; use App\Enums\PoolCandidateSearchStatus; -use App\Enums\PoolStream; use App\Models\ApplicantFilter; use App\Models\Classification; use App\Models\Community; use App\Models\Department; use App\Models\PoolCandidateSearchRequest; use App\Models\User; +use App\Models\WorkStream; use Database\Seeders\ClassificationSeeder; use Database\Seeders\DepartmentSeeder; use Database\Seeders\RolePermissionSeeder; @@ -299,13 +299,14 @@ public function testSearchRequestClassificationsFiltering(): void public function testSearchRequestStreamsFiltering(): void { - $applicantFilter1 = ApplicantFilter::factory()->create([ - 'qualified_streams' => [PoolStream::SECURITY->name], - ]); - $applicantFilter2 = ApplicantFilter::factory()->create([ - 'qualified_streams' => [PoolStream::BUSINESS_ADVISORY_SERVICES->name], - ]); + $stream1 = WorkStream::factory()->create(); + + $applicantFilter1 = ApplicantFilter::factory()->withWorkStreams([$stream1])->create(); + + $stream2 = WorkStream::factory()->create(); + + $applicantFilter2 = ApplicantFilter::factory()->withWorkStreams([$stream2])->create(); PoolCandidateSearchRequest::factory()->count(1)->create([ 'applicant_filter_id' => $applicantFilter1->id, @@ -316,16 +317,18 @@ public function testSearchRequestStreamsFiltering(): void // streams null results in 3 results $this->actingAs($this->requestResponder, 'api') - ->graphQL($this->searchRequestQuery, ['where' => ['streams' => null]]) + ->graphQL($this->searchRequestQuery, ['where' => ['workStreams' => null]]) ->assertJsonFragment(['count' => 3]); + $unattachedStream = WorkStream::factory()->create(); + // infrastructure passed in returns 0 results $this->actingAs($this->requestResponder, 'api') ->graphQL( $this->searchRequestQuery, [ 'where' => [ - 'streams' => [PoolStream::INFRASTRUCTURE_OPERATIONS->name], + 'workStreams' => [$unattachedStream->id], ], ] ) @@ -337,7 +340,7 @@ public function testSearchRequestStreamsFiltering(): void $this->searchRequestQuery, [ 'where' => [ - 'streams' => [PoolStream::SECURITY->name], + 'workStreams' => [$stream1->id], ], ] ) @@ -349,7 +352,7 @@ public function testSearchRequestStreamsFiltering(): void $this->searchRequestQuery, [ 'where' => [ - 'streams' => [PoolStream::SECURITY->name, PoolStream::INFRASTRUCTURE_OPERATIONS->name], + 'workStreams' => [$stream1->id, $unattachedStream->id], ], ] ) @@ -361,7 +364,7 @@ public function testSearchRequestStreamsFiltering(): void $this->searchRequestQuery, [ 'where' => [ - 'streams' => [PoolStream::SECURITY->name, PoolStream::BUSINESS_ADVISORY_SERVICES->name], + 'workStreams' => [$stream1->id, $stream2->id], ], ] ) diff --git a/api/tests/Feature/PoolCandidateTest.php b/api/tests/Feature/PoolCandidateTest.php index 3428eb22f83..19ef7397176 100644 --- a/api/tests/Feature/PoolCandidateTest.php +++ b/api/tests/Feature/PoolCandidateTest.php @@ -20,6 +20,8 @@ use Tests\TestCase; use Tests\UsesProtectedGraphqlEndpoint; +use function PHPUnit\Framework\assertEqualsCanonicalizing; + class PoolCandidateTest extends TestCase { use MakesGraphQLRequests; @@ -639,6 +641,7 @@ public function testOrderByPoolName(): void name { en fr + localized } } } @@ -848,4 +851,35 @@ public function testScopeCandidatesInCommunity(): void ])->assertJsonFragment(['total' => 1]) ->assertJsonFragment(['id' => $communityCandidate->id]); } + + // test scopeAvailable + public function testScopeAvailable(): void + { + PoolCandidate::truncate(); + $candidate = PoolCandidate::factory()->availableInSearch()->create([ + 'pool_candidate_status' => PoolCandidateStatus::PLACED_TERM->name, + 'expiry_date' => null, + 'suspended_at' => null, + ]); + + $suspendedCandidate = PoolCandidate::factory()->availableInSearch()->create([ + 'pool_candidate_status' => PoolCandidateStatus::PLACED_TERM->name, + 'expiry_date' => null, + 'suspended_at' => config('constants.far_past_datetime'), + ]); + + $expiredCandidate = PoolCandidate::factory()->availableInSearch()->create([ + 'pool_candidate_status' => PoolCandidateStatus::PLACED_TERM->name, + 'expiry_date' => config('constants.past_date'), + 'suspended_at' => null, + ]); + + $queryBuilder = PoolCandidate::query(); + $candidateIds = PoolCandidate::scopeAvailable($queryBuilder)->get()->pluck('id')->toArray(); + + // suspended and expired not present + assertEqualsCanonicalizing([ + $candidate->id, + ], $candidateIds); + } } diff --git a/api/tests/Feature/PoolCandidateUpdateTest.php b/api/tests/Feature/PoolCandidateUpdateTest.php index 770bf98d916..34735e8e7c9 100644 --- a/api/tests/Feature/PoolCandidateUpdateTest.php +++ b/api/tests/Feature/PoolCandidateUpdateTest.php @@ -160,6 +160,7 @@ protected function setUp(): void placedDepartment { id } + suspendedAt } } '; @@ -175,6 +176,7 @@ protected function setUp(): void placedDepartment { id } + suspendedAt } } '; @@ -502,12 +504,66 @@ public function testPlaceCandidateMutation(): void assertSame($response['placedDepartment']['id'], $department->id); } + // placing candidates sets suspended_at automatically or keeps/makes it null appropriately + public function testPlaceCandidateMutationSuspensionLogic(): void + { + $department = Department::factory()->create(); + $this->poolCandidate->pool_candidate_status = PoolCandidateStatus::QUALIFIED_AVAILABLE->name; + $this->poolCandidate->placed_at = null; + $this->poolCandidate->save(); + $placedDoNotSuspend = [ + PlacementType::PLACED_TENTATIVE->name, + PlacementType::PLACED_CASUAL->name, + ]; + $placedDoSuspend = [ + PlacementType::PLACED_TERM->name, + PlacementType::PLACED_INDETERMINATE->name, + ]; + + foreach ($placedDoNotSuspend as $placementType) { + $response = $this->actingAs($this->poolOperatorUser, 'api') + ->graphQL( + $this->placeCandidateMutation, + [ + 'id' => $this->poolCandidate->id, + 'placeCandidate' => [ + 'placementType' => $placementType, + 'departmentId' => $department->id, + ], + ] + )->json('data.placeCandidate'); + + assertSame($response['status']['value'], $placementType); + assertNotNull($response['placedAt']); + assertNull($response['suspendedAt']); + } + + foreach ($placedDoSuspend as $placementType) { + $response = $this->actingAs($this->poolOperatorUser, 'api') + ->graphQL( + $this->placeCandidateMutation, + [ + 'id' => $this->poolCandidate->id, + 'placeCandidate' => [ + 'placementType' => $placementType, + 'departmentId' => $department->id, + ], + ] + )->json('data.placeCandidate'); + + assertSame($response['status']['value'], $placementType); + assertNotNull($response['placedAt']); + assertNotNull($response['suspendedAt']); + } + } + public function testRevertPlaceCandidateMutation(): void { $department = Department::factory()->create(); $this->poolCandidate->pool_candidate_status = PoolCandidateStatus::NEW_APPLICATION->name; $this->poolCandidate->placed_department_id = $department->id; $this->poolCandidate->placed_at = config('constants.far_past_date'); + $this->poolCandidate->suspended_at = config('constants.far_past_date'); $this->poolCandidate->save(); // cannot execute mutation due to candidate not being placed @@ -535,6 +591,7 @@ public function testRevertPlaceCandidateMutation(): void assertSame($response['status']['value'], PoolCandidateStatus::QUALIFIED_AVAILABLE->name); assertNull($response['placedAt']); assertNull($response['placedDepartment']); + assertNull($response['suspendedAt']); } public function testQualifyCandidateMutation(): void diff --git a/api/tests/Feature/PoolTest.php b/api/tests/Feature/PoolTest.php index 1fcf719ac4e..bb491d03bf9 100644 --- a/api/tests/Feature/PoolTest.php +++ b/api/tests/Feature/PoolTest.php @@ -3,7 +3,6 @@ namespace Tests\Feature; use App\Enums\PoolStatus; -use App\Enums\PoolStream; use App\Enums\PublishingGroup; use App\Enums\SkillCategory; use App\Models\Classification; @@ -14,6 +13,7 @@ use App\Models\Skill; use App\Models\Team; use App\Models\User; +use App\Models\WorkStream; use Carbon\Carbon; use Database\Helpers\ApiErrorEnums; use Database\Seeders\RolePermissionSeeder; @@ -1099,7 +1099,7 @@ public function testPoolNameScope(): void poolsPaginated(where: $where) { data { id - name { en fr } + name { en fr localized } } } } @@ -1159,16 +1159,20 @@ public function testPoolTeamScope(): void */ public function testPoolStreamsScope(): void { - $ATIP = Pool::factory()->published()->create([ - 'stream' => PoolStream::ACCESS_INFORMATION_PRIVACY->name, + $stream1 = WorkStream::factory()->create(); + $stream2 = WorkStream::factory()->create(); + $unassociatedStream = WorkStream::factory()->create(); + + $pool1 = Pool::factory()->published()->create([ + 'work_stream_id' => $stream1->id, ]); - $BAS = Pool::factory()->published()->create([ - 'stream' => PoolStream::BUSINESS_ADVISORY_SERVICES->name, + $pool2 = Pool::factory()->published()->create([ + 'work_stream_id' => $stream2->id, ]); Pool::factory()->published()->create([ - 'stream' => PoolStream::DATABASE_MANAGEMENT->name, + 'work_stream_id' => $unassociatedStream->id, ]); $res = $this->graphQL( @@ -1178,31 +1182,31 @@ public function testPoolStreamsScope(): void poolsPaginated(where: $where) { data { id - stream { value } + workStream { id } } } } ', [ 'where' => [ - 'streams' => [ - PoolStream::ACCESS_INFORMATION_PRIVACY->name, - PoolStream::BUSINESS_ADVISORY_SERVICES->name, + 'workStreams' => [ + $stream1->id, + $stream2->id, ], ], ] )->assertJsonFragment([ 'data' => [ [ - 'id' => $ATIP->id, - 'stream' => [ - 'value' => PoolStream::ACCESS_INFORMATION_PRIVACY->name, + 'id' => $pool1->id, + 'workStream' => [ + 'id' => $stream1->id, ], ], [ - 'id' => $BAS->id, - 'stream' => [ - 'value' => PoolStream::BUSINESS_ADVISORY_SERVICES->name, + 'id' => $pool2->id, + 'workStream' => [ + 'id' => $stream2->id, ], ], ], diff --git a/api/tests/Feature/SnapshotTest.php b/api/tests/Feature/SnapshotTest.php index 83e10b6d485..5c90d6f58e8 100644 --- a/api/tests/Feature/SnapshotTest.php +++ b/api/tests/Feature/SnapshotTest.php @@ -88,6 +88,7 @@ public function testCreateSnapshot() )->json('data.poolCandidate.profileSnapshot'); $decodedActual = json_decode($actualSnapshot, true); + $this->unsetLocalizedKey($decodedActual); // Add version number $expectedSnapshot['version'] = ProfileSnapshot::$VERSION; @@ -250,4 +251,16 @@ public function testLocalizingLegacyEnums() ], ], $snapshot); } + + private function unsetLocalizedKey(array &$arr) + { + if (is_array($arr)) { + unset($arr['localized']); + } + foreach ($arr as &$v) { + if (is_array($v)) { + $this->unsetLocalizedKey($v); + } + } + } } diff --git a/api/tests/Feature/UserTest.php b/api/tests/Feature/UserTest.php index fe8c3148f3b..4363eea456b 100644 --- a/api/tests/Feature/UserTest.php +++ b/api/tests/Feature/UserTest.php @@ -1729,6 +1729,7 @@ public function testCountApplicantsQuery(): void 'user_id' => $user['id'], ]); + // group one PoolCandidate::factory()->count(8)->create([ 'pool_id' => $pool1['id'], 'expiry_date' => config('constants.far_future_date'), @@ -1739,6 +1740,7 @@ public function testCountApplicantsQuery(): void 'looking_for_bilingual' => false, ]), ]); + // group two PoolCandidate::factory()->count(5)->create([ 'pool_id' => $pool1['id'], 'expiry_date' => config('constants.far_future_date'), @@ -1750,6 +1752,7 @@ public function testCountApplicantsQuery(): void ]), ]); // Should appear in searches, but in pool 2. + // group three PoolCandidate::factory()->create([ 'pool_id' => $pool2['id'], 'expiry_date' => config('constants.far_future_date'), @@ -1761,6 +1764,7 @@ public function testCountApplicantsQuery(): void ]), ]); // Expired in pool - should not appear in searches + // group four PoolCandidate::factory()->create([ 'pool_id' => $pool1['id'], 'expiry_date' => '2000-01-01', @@ -1771,11 +1775,13 @@ public function testCountApplicantsQuery(): void 'looking_for_bilingual' => false, ]), ]); - // Already placed - should not appear in searches + // Already placed - should appear in searches + // group five PoolCandidate::factory()->create([ 'pool_id' => $pool1['id'], 'expiry_date' => config('constants.far_future_date'), 'pool_candidate_status' => PoolCandidateStatus::PLACED_TERM->name, + 'suspended_at' => null, 'user_id' => User::factory([ 'looking_for_english' => true, 'looking_for_french' => false, @@ -1783,6 +1789,7 @@ public function testCountApplicantsQuery(): void ]), ]); // User status inactive - should not appear in searches + // group six PoolCandidate::factory()->create([ 'pool_id' => $pool1['id'], 'expiry_date' => config('constants.far_future_date'), @@ -1812,7 +1819,8 @@ public function testCountApplicantsQuery(): void ); $response->assertJson([ 'data' => [ - 'countApplicants' => 14, // including base admin user + // contains groups one, two, and five + 'countApplicants' => 15, // including base admin user ], ]); @@ -1834,7 +1842,8 @@ public function testCountApplicantsQuery(): void ] )->assertJson([ 'data' => [ - 'countApplicants' => 9, //including base admin user + // counts groups one and five, filtered out two due to added language + 'countApplicants' => 10, // including base admin user ], ]); } diff --git a/api/tests/Feature/WorkExperienceTest.php b/api/tests/Feature/WorkExperienceTest.php index 8a4edc64cf9..cf463bfee8c 100644 --- a/api/tests/Feature/WorkExperienceTest.php +++ b/api/tests/Feature/WorkExperienceTest.php @@ -6,6 +6,7 @@ use App\Enums\EmploymentCategory; use App\Enums\ExternalRoleSeniority; use App\Enums\ExternalSizeOfOrganization; +use App\Enums\GovPositionType; use App\Enums\WorkExperienceGovEmployeeType; use App\Models\Classification; use App\Models\Department; @@ -146,6 +147,31 @@ public function testCreatingExperienceFailsValidatingRequired(): void )->assertGraphQLValidationError('workExperience.extRoleSeniority', 'The work experience.ext role seniority field is required.'); } + // test that validation rejects creating experiences with substantive position type when gov employee type is term + public function testCreatingExperienceFailsValidatingGovPositionType(): void + { + $this->actingAs($this->admin, 'api')->graphQL( + /** @lang GraphQL */ + ' + mutation createWorkExperience($userId: ID!, $workExperience: WorkExperienceInput!) { + createWorkExperience(userId: $userId, workExperience: $workExperience) { + user { + id + } + } + } + ', + [ + 'userId' => $this->admin->id, + 'workExperience' => [ + 'employmentCategory' => EmploymentCategory::GOVERNMENT_OF_CANADA->name, + 'govEmploymentType' => WorkExperienceGovEmployeeType::TERM->name, + 'govPositionType' => GovPositionType::SUBSTANTIVE->name, + ], + ] + )->assertGraphQLValidationError('workExperience.govPositionType', 'The selected work experience.gov position type is invalid.'); + } + // test that a created work experience of government type queries without issue public function testQueryingCreatedExperienceGovernment(): void { @@ -169,8 +195,9 @@ public function testQueryingCreatedExperienceGovernment(): void 'workExperience' => [ 'employmentCategory' => EmploymentCategory::GOVERNMENT_OF_CANADA->name, 'govEmploymentType' => WorkExperienceGovEmployeeType::TERM->name, - 'classification' => ['connect' => $classification->id], - 'department' => ['connect' => $department->id], + 'govPositionType' => GovPositionType::ACTING->name, + 'classificationId' => $classification->id, + 'departmentId' => $department->id, ], ] )->assertJsonFragment( diff --git a/api/tests/Unit/PoolCandidatePolicyTest.php b/api/tests/Unit/PoolCandidatePolicyTest.php index 76f94f6bb35..a8068a1be4d 100644 --- a/api/tests/Unit/PoolCandidatePolicyTest.php +++ b/api/tests/Unit/PoolCandidatePolicyTest.php @@ -73,8 +73,8 @@ protected function setUp(): void ]); $this->team = Team::factory()->create(['name' => 'test-team']); - $this->community = Community::factory()->create(['name' => 'test-team']); - $this->otherCommunity = Community::factory()->create(['name' => 'suspicious-team']); + $this->community = Community::factory()->create(['name' => ['en' => 'test-team EN', 'fr' => 'test-team FR']]); + $this->otherCommunity = Community::factory()->create(['name' => ['en' => 'suspicious-team EN', 'fr' => 'suspicious-team FR']]); $this->poolOperatorUser = User::factory() ->asPoolOperator($this->team->name) diff --git a/api/tests/Unit/PoolPolicyTest.php b/api/tests/Unit/PoolPolicyTest.php index 6f0bca92972..688cfd58aa3 100644 --- a/api/tests/Unit/PoolPolicyTest.php +++ b/api/tests/Unit/PoolPolicyTest.php @@ -67,8 +67,8 @@ protected function setUp(): void ]); $this->team = Team::factory()->create(['name' => 'test-team']); - $this->community = Community::factory()->create(['name' => 'test-team']); - $this->otherCommunity = Community::factory()->create(['name' => 'suspicious-team']); + $this->community = Community::factory()->create(); + $this->otherCommunity = Community::factory()->create(); $this->poolOperatorUser = User::factory() ->asApplicant() diff --git a/apps/playwright/fixtures/ExperiencePage.ts b/apps/playwright/fixtures/ExperiencePage.ts index 235022e06e6..0fe6bdf3d31 100644 --- a/apps/playwright/fixtures/ExperiencePage.ts +++ b/apps/playwright/fixtures/ExperiencePage.ts @@ -1,4 +1,4 @@ -import { Locator, type Page } from "@playwright/test"; +import { Locator, type Page, expect } from "@playwright/test"; import { InputMaybe, @@ -41,7 +41,12 @@ class ExperiencePage extends AppPage { await this.waitForGraphqlResponse("ExperienceFormData"); } - async addWorkExperience(input: WorkExperienceInput) { + async edit(id: string) { + await this.page.goto(`/en/applicant/career-timeline/${id}/edit`); + await this.waitForGraphqlResponse("ExperienceFormData"); + } + + async addExternalWorkExperience(input: WorkExperienceInput) { await this.create(); await this.typeLocator.selectOption("work"); @@ -49,16 +54,148 @@ class ExperiencePage extends AppPage { .getByRole("textbox", { name: /my role/i }) .fill(input.role ?? "test role"); + await this.page + .getByRole("group", { name: /employment category/i }) + .getByRole("radio", { + name: /This was a role with an external organization/i, + }) + .click(); + await this.page .getByRole("textbox", { name: /organization/i }) - .fill(input?.organization ?? "test org"); + .fill(input.organization ?? "test org"); + + await this.page + .getByRole("textbox", { name: /team, group, or division/i }) + .fill(input.division ?? "test team"); + + await this.page + .getByRole("group", { name: /size of the organization/i }) + .getByRole("radio", { + name: /1-35 employees/i, + }) + .click(); + + await this.page + .getByRole("group", { name: /seniority of the role/i }) + .getByRole("radio", { + name: /intern or co-op/i, + }) + .click(); - if (input.division) { + await this.fillDate(input.startDate); + + if (!input.endDate) { await this.page - .getByRole("textbox", { name: /team, group, or division/i }) - .fill(input.division); + .getByRole("checkbox", { name: /i am currently active in this role/i }) + .click(); + } else { + await this.fillDate(input.endDate, true); } + await this.page + .getByRole("textbox", { name: /additional details/i }) + .fill(input.details ?? "test details"); + + await this.save(); + await this.waitForGraphqlResponse("CreateWorkExperience"); + } + + async addGovStudentWorkExperience(input: WorkExperienceInput) { + await this.create(); + await this.typeLocator.selectOption("work"); + + await this.page + .getByRole("textbox", { name: /my role/i }) + .fill(input.role ?? "test role"); + + await this.page + .getByRole("group", { name: /employment category/i }) + .getByRole("radio", { + name: /this was a role with the government of canada/i, + }) + .click(); + + await this.page + .getByRole("combobox", { name: /department/i }) + .selectOption({ label: "Treasury Board Secretariat" }); + + await this.page + .getByRole("textbox", { name: /team, group, or division/i }) + .fill(input.division ?? "test team"); + + await this.page + .getByRole("group", { name: /employment type/i }) + .getByRole("radio", { + name: /student/i, + }) + .click(); + + await this.fillDate(input.startDate); + + await this.page + .getByRole("checkbox", { name: /i am currently active in this role/i }) + .click(); + + // Ensure label changes to "Expected end date" when currently active in the role is selected + await expect( + this.page.getByRole("group", { name: /end date/i }), + ).toContainText("Expected end date"); + + await this.fillDate(input.endDate, true); + + await this.page + .getByRole("textbox", { name: /additional details/i }) + .fill(input.details ?? "test details"); + + await this.save(); + await this.waitForGraphqlResponse("CreateWorkExperience"); + } + + async addGovCasualWorkExperience(input: WorkExperienceInput) { + await this.create(); + await this.typeLocator.selectOption("work"); + + await this.page + .getByRole("textbox", { name: /my role/i }) + .fill(input.role ?? "test role"); + + await this.page + .getByRole("group", { name: /employment category/i }) + .getByRole("radio", { + name: /this was a role with the government of canada/i, + }) + .click(); + + await this.page + .getByRole("combobox", { name: /department/i }) + .selectOption({ label: "Treasury Board Secretariat" }); + + await this.page + .getByRole("textbox", { name: /team, group, or division/i }) + .fill(input.division ?? "test team"); + + await this.page + .getByRole("group", { name: /employment type/i }) + .getByRole("radio", { + name: /casual/i, + }) + .click(); + + await this.page + .getByRole("combobox", { name: /group/i }) + .selectOption({ label: "IT" }); + await this.page + .getByRole("combobox", { name: /level/i }) + .selectOption({ label: "1" }); + + await this.page + .getByRole("group", { name: /employment type/i }) + .getByRole("radio", { + name: /casual/i, + }) + .click(); + await this.fillDate(input.startDate); if (!input.endDate) { @@ -77,6 +214,284 @@ class ExperiencePage extends AppPage { await this.waitForGraphqlResponse("CreateWorkExperience"); } + async addGovTermOrIndeterminateWorkExperience(input: WorkExperienceInput) { + await this.create(); + await this.typeLocator.selectOption("work"); + + await this.page + .getByRole("textbox", { name: /my role/i }) + .fill(input.role ?? "test role"); + + await this.page + .getByRole("group", { name: /employment category/i }) + .getByRole("radio", { + name: /this was a role with the government of canada/i, + }) + .click(); + + await this.page + .getByRole("combobox", { name: /department/i }) + .selectOption({ label: "Treasury Board Secretariat" }); + + await this.page + .getByRole("textbox", { name: /team, group, or division/i }) + .fill(input.division ?? "test team"); + + // Set the employment type to "Term" + await this.page + .getByRole("group", { name: /employment type/i }) + .getByRole("radio", { + name: /^term$/i, + }) + .click(); + + // Ensure "Substantive" option is removed from position type group + // when employment type is "Term" + await expect( + this.page.getByRole("group", { name: /position type/i }), + ).not.toContainText("Substantive"); + + await this.page + .getByRole("group", { name: /position type/i }) + .getByRole("radio", { + name: /acting/i, + }) + .click(); + + // Change the employment type to "Indeterminate" + await this.page + .getByRole("group", { name: /employment type/i }) + .getByRole("radio", { + name: /^indeterminate$/i, + }) + .click(); + + await this.page + .getByRole("group", { name: /position type/i }) + .getByRole("radio", { + name: /substantive/i, + }) + .click(); + + await this.page + .getByRole("combobox", { name: /group/i }) + .selectOption({ label: "IT" }); + await this.page + .getByRole("combobox", { name: /level/i }) + .selectOption({ label: "1" }); + + await this.fillDate(input.startDate); + + if (!input.endDate) { + await this.page + .getByRole("checkbox", { name: /i am currently active in this role/i }) + .click(); + } else { + await this.fillDate(input.endDate, true); + } + + await this.page + .getByRole("textbox", { name: /additional details/i }) + .fill(input.details ?? "test details"); + + await this.save(); + await this.waitForGraphqlResponse("CreateWorkExperience"); + } + + async addGovContractorWorkExperience(input: WorkExperienceInput) { + await this.create(); + await this.typeLocator.selectOption("work"); + + await this.page + .getByRole("textbox", { name: /my role/i }) + .fill(input.role ?? "test role"); + + await this.page + .getByRole("group", { name: /employment category/i }) + .getByRole("radio", { + name: /this was a role with the government of canada/i, + }) + .click(); + + await this.page + .getByRole("combobox", { name: /department/i }) + .selectOption({ label: "Treasury Board Secretariat" }); + + await this.page + .getByRole("textbox", { name: /team, group, or division/i }) + .fill(input.division ?? "test team"); + + // Set the employment type to "Term" + await this.page + .getByRole("group", { name: /employment type/i }) + .getByRole("radio", { + name: /contractor/i, + }) + .click(); + + await this.page + .getByRole("group", { name: /seniority of the role/i }) + .getByRole("radio", { + name: /intern or co-op/i, + }) + .click(); + + await this.page + .getByRole("group", { name: /contractor type/i }) + .getByRole("radio", { + name: /self-employed/i, + }) + .click(); + + // Ensure contracting firm or agency text input isn't rendered + await expect( + this.page.getByRole("textbox", { name: /contracting firm or agency/i }), + ).toBeHidden(); + + await this.page + .getByRole("group", { name: /contractor type/i }) + .getByRole("radio", { + name: /firm or agency/i, + }) + .click(); + + await this.page + .getByRole("textbox", { name: /contracting firm or agency/i }) + .fill("test contracting firm"); + + await this.fillDate(input.startDate); + + if (!input.endDate) { + await this.page + .getByRole("checkbox", { name: /i am currently active in this role/i }) + .click(); + } else { + await this.fillDate(input.endDate, true); + } + + await this.page + .getByRole("textbox", { name: /additional details/i }) + .fill(input.details ?? "test details"); + + await this.save(); + await this.waitForGraphqlResponse("CreateWorkExperience"); + } + + async addCafWorkExperience(input: WorkExperienceInput) { + await this.create(); + await this.typeLocator.selectOption("work"); + + await this.page + .getByRole("textbox", { name: /my role/i }) + .fill(input.role ?? "test role"); + + await this.page + .getByRole("group", { name: /employment category/i }) + .getByRole("radio", { + name: /this was a role with the canadian armed forces/i, + }) + .click(); + + await this.page + .getByRole("group", { name: /employment type/i }) + .getByRole("radio", { + name: /regular force/i, + }) + .click(); + + await this.page + .getByRole("group", { name: /military force/i }) + .getByRole("radio", { + name: /canadian army/i, + }) + .click(); + + await this.page + .getByRole("group", { name: /rank category/i }) + .getByRole("radio", { + name: /general or flag officer/i, + }) + .click(); + + await this.fillDate(input.startDate); + + if (!input.endDate) { + await this.page + .getByRole("checkbox", { name: /i am currently active in this role/i }) + .click(); + } else { + await this.fillDate(input.endDate, true); + } + + await this.page + .getByRole("textbox", { name: /additional details/i }) + .fill(input.details ?? "test details"); + + await this.save(); + await this.waitForGraphqlResponse("CreateWorkExperience"); + } + + async editWorkExperience(id: string, input: WorkExperienceInput) { + await this.edit(id); + + await this.page + .getByRole("textbox", { name: /my role/i }) + .fill(input.role ?? "edit test role"); + + await this.page + .getByRole("group", { name: /employment category/i }) + .getByRole("radio", { + name: /this was a role with the government of canada/i, + }) + .click(); + + await this.page + .getByRole("combobox", { name: /department/i }) + .selectOption({ label: "Treasury Board Secretariat" }); + + await this.page + .getByRole("textbox", { name: /team, group, or division/i }) + .fill(input.division ?? "test team"); + + await this.page + .getByRole("group", { name: /employment type/i }) + .getByRole("radio", { + name: /casual/i, + }) + .click(); + + await this.page + .getByRole("combobox", { name: /group/i }) + .selectOption({ label: "IT" }); + await this.page + .getByRole("combobox", { name: /level/i }) + .selectOption({ label: "1" }); + + await this.page + .getByRole("group", { name: /employment type/i }) + .getByRole("radio", { + name: /casual/i, + }) + .click(); + + await this.fillDate(input.startDate); + + if (!input.endDate) { + await this.page + .getByRole("checkbox", { name: /i am currently active in this role/i }) + .click(); + } else { + await this.fillDate(input.endDate, true); + } + + await this.page + .getByRole("textbox", { name: /additional details/i }) + .fill(input.details ?? "test details"); + + await this.save(); + await this.waitForGraphqlResponse("UpdateWorkExperience"); + } + async addPersonalExperience(input: PersonalExperienceInput) { await this.create(); await this.typeLocator.selectOption("personal"); @@ -223,7 +638,7 @@ class ExperiencePage extends AppPage { await this.waitForGraphqlResponse("CreateEducationExperience"); } - async linkSkilltoExperience(input: { + async linkSkillToExperience(input: { experienceType: string; skill: string; }) { diff --git a/apps/playwright/playwright.config.ts b/apps/playwright/playwright.config.ts index 0233317a407..7405ee069f5 100644 --- a/apps/playwright/playwright.config.ts +++ b/apps/playwright/playwright.config.ts @@ -3,6 +3,7 @@ import path from "path"; import { defineConfig, devices } from "@playwright/test"; import dotenv from "dotenv"; +// eslint-disable-next-line import/no-named-as-default-member dotenv.config({ path: path.resolve(__dirname, ".env") }); /** @@ -20,7 +21,7 @@ export default defineConfig({ workers: process.env.CI ? 1 : "25%", /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: process.env.CI - ? [["line"], ["html", { open: "never" }]] + ? "blob" : [["line"], ["html", { open: "on-failure" }]], timeout: Number(process.env.TEST_TIMEOUT ?? 60 * 1000), // 1 minute expect: { timeout: Number(process.env.EXPECT_TIMEOUT ?? 10000) }, // 10 seconds @@ -43,10 +44,10 @@ export default defineConfig({ use: { ...devices["Desktop Chrome"] }, }, - { - name: "firefox", - use: { ...devices["Desktop Firefox"] }, - }, + // { + // name: "firefox", + // use: { ...devices["Desktop Firefox"] }, + // }, { name: "webkit", diff --git a/apps/playwright/tests/admin/pool-candidate.spec.ts b/apps/playwright/tests/admin/pool-candidate.spec.ts index 3e97214a579..e0c88280dd2 100644 --- a/apps/playwright/tests/admin/pool-candidate.spec.ts +++ b/apps/playwright/tests/admin/pool-candidate.spec.ts @@ -224,7 +224,7 @@ test.describe("Pool candidates", () => { await appPage.page.getByRole("button", { name: "Save changes" }).click(); await appPage.waitForGraphqlResponse("PoolCandidate_UpdateNotes"); await expect( - appPage.page.getByRole("button", { name: "Edit notes" }), + appPage.page.getByRole("button", { name: /edit notes/i }), ).toBeVisible(); await expect(appPage.page.getByText(/Notes notes notes/i)).toBeVisible(); }); @@ -371,8 +371,9 @@ test.describe("Pool candidates", () => { await expect( appPage.page.getByRole("button", { name: "Removed", exact: true }), ).toBeHidden(); + await appPage.waitForGraphqlResponse("ReinstateCandidate"); await expect( - appPage.page.getByRole("button", { name: "Record final decision" }), + appPage.page.getByRole("button", { name: /remove candidate/i }), ).toBeVisible(); }); }); diff --git a/apps/playwright/tests/applicant/experience.spec.ts b/apps/playwright/tests/applicant/experience.spec.ts index 7972623de1f..32dfe3d7009 100644 --- a/apps/playwright/tests/applicant/experience.spec.ts +++ b/apps/playwright/tests/applicant/experience.spec.ts @@ -1,16 +1,20 @@ +import { WorkExperience } from "@gc-digital-talent/graphql"; + import { test, expect } from "~/fixtures"; import ExperiencePage from "~/fixtures/ExperiencePage"; import { loginBySub } from "~/utils/auth"; +import graphql from "~/utils/graphql"; +import { me } from "~/utils/user"; test.describe("Experiences", () => { const uniqueTestId = Date.now().valueOf(); - test("Can create work experience", async ({ appPage }) => { - const role = `Test add work experience (${uniqueTestId})`; + test("Can create external work experience", async ({ appPage }) => { + const role = `Test add external work experience (${uniqueTestId})`; const experiencePage = new ExperiencePage(appPage.page); await loginBySub(experiencePage.page, "applicant@test.com"); - await experiencePage.addWorkExperience({ + await experiencePage.addExternalWorkExperience({ role, startDate: "2001-01", }); @@ -20,6 +24,117 @@ test.describe("Experiences", () => { ); }); + test("Can create goc student work experience", async ({ appPage }) => { + const role = `Test add goc student work experience (${uniqueTestId})`; + const experiencePage = new ExperiencePage(appPage.page); + await loginBySub(experiencePage.page, "applicant@test.com"); + + await experiencePage.addGovStudentWorkExperience({ + role, + startDate: "2001-01", + endDate: "2200-01", + }); + + await expect(experiencePage.page.getByRole("alert")).toContainText( + /successfully added experience/i, + ); + }); + + test("Can create goc casual work experience", async ({ appPage }) => { + const role = `Test add goc casual work experience (${uniqueTestId})`; + const experiencePage = new ExperiencePage(appPage.page); + await loginBySub(experiencePage.page, "applicant@test.com"); + + await experiencePage.addGovCasualWorkExperience({ + role, + startDate: "2001-01", + endDate: "2023-01", + }); + + await expect(experiencePage.page.getByRole("alert")).toContainText( + /successfully added experience/i, + ); + }); + + test("Can create goc term or indeterminate work experience", async ({ + appPage, + }) => { + const role = `Test add goc term or indeterminate work experience (${uniqueTestId})`; + const experiencePage = new ExperiencePage(appPage.page); + await loginBySub(experiencePage.page, "applicant@test.com"); + + await experiencePage.addGovTermOrIndeterminateWorkExperience({ + role, + startDate: "2001-01", + endDate: "2023-01", + }); + + await expect(experiencePage.page.getByRole("alert")).toContainText( + /successfully added experience/i, + ); + }); + + test("Can create goc contractor work experience", async ({ appPage }) => { + const role = `Test add goc contractor work experience (${uniqueTestId})`; + const experiencePage = new ExperiencePage(appPage.page); + await loginBySub(experiencePage.page, "applicant@test.com"); + + await experiencePage.addGovContractorWorkExperience({ + role, + startDate: "2001-01", + endDate: "2023-01", + }); + + await expect(experiencePage.page.getByRole("alert")).toContainText( + /successfully added experience/i, + ); + }); + + test("Can create caf work experience", async ({ appPage }) => { + const role = `Test add caf work experience (${uniqueTestId})`; + const experiencePage = new ExperiencePage(appPage.page); + await loginBySub(experiencePage.page, "applicant@test.com"); + + await experiencePage.addCafWorkExperience({ + role, + startDate: "2001-01", + }); + + await expect(experiencePage.page.getByRole("alert")).toContainText( + /successfully added experience/i, + ); + }); + + test("Can edit work experience", async ({ appPage }) => { + const role = `Test edit work experience (${uniqueTestId})`; + const experiencePage = new ExperiencePage(appPage.page); + await loginBySub(experiencePage.page, "applicant@test.com"); + + await experiencePage.addCafWorkExperience({ + role, + startDate: "2001-01", + }); + + await expect(experiencePage.page.getByRole("alert")).toContainText( + /successfully added experience/i, + ); + + await experiencePage.goToIndex(); + + const applicantCtx = await graphql.newContext("applicant@test.com"); + const applicant = await me(applicantCtx, {}); + + const workExperience = applicant.experiences?.find( + (ex: WorkExperience) => ex?.role === role, + ); + + await experiencePage.editWorkExperience(`${workExperience?.id}`, { + role, + startDate: "2001-01", + endDate: "2200-01", + }); + }); + test("Can create personal experience", async ({ appPage }) => { const title = `Test add personal experience (${uniqueTestId})`; const experiencePage = new ExperiencePage(appPage.page); @@ -84,7 +199,7 @@ test.describe("Experiences", () => { const skill = "Courage"; - await experiencePage.linkSkilltoExperience({ + await experiencePage.linkSkillToExperience({ experienceType: "work", skill: skill, }); diff --git a/apps/playwright/tests/search-workflows.spec.ts b/apps/playwright/tests/search-workflows.spec.ts index f36a64270d5..c34364f6320 100644 --- a/apps/playwright/tests/search-workflows.spec.ts +++ b/apps/playwright/tests/search-workflows.spec.ts @@ -9,6 +9,7 @@ import { PoolCandidateStatus, Skill, SkillCategory, + WorkStream, } from "@gc-digital-talent/graphql"; import { test, expect } from "~/fixtures"; @@ -21,12 +22,14 @@ import { createUserWithRoles, me } from "~/utils/user"; import graphql from "~/utils/graphql"; import { createAndPublishPool } from "~/utils/pools"; import { getClassifications } from "~/utils/classification"; +import { getWorkStreams } from "~/utils/workStreams"; test.describe("Talent search", () => { const uniqueTestId = Date.now().valueOf(); const sub = `playwright.sub.${uniqueTestId}`; const poolName = `Search pool ${uniqueTestId}`; let classification: Classification; + let workStream: WorkStream; let skill: Skill | undefined; const expectNoCandidate = async (page: Page) => { @@ -79,12 +82,16 @@ test.describe("Talent search", () => { const classifications = await getClassifications(adminCtx, {}); classification = classifications[0]; + const workStreams = await getWorkStreams(adminCtx, {}); + workStream = workStreams[0]; + const adminUser = await me(adminCtx, {}); // Accepted pool const createdPool = await createAndPublishPool(adminCtx, { userId: adminUser.id, skillIds: technicalSkill ? [technicalSkill?.id] : undefined, classificationId: classification.id, + workStreamId: workStream.id, name: { en: poolName, fr: `${poolName} (FR)`, @@ -138,7 +145,7 @@ test.describe("Talent search", () => { await expectNoCandidate(appPage.page); await streamFilter.selectOption({ - label: "Business Line Advisory Services", + label: workStream.name?.en ?? "", }); await expect(poolCard).toBeVisible(); @@ -221,7 +228,7 @@ test.describe("Talent search", () => { ).toBeVisible(); await expect( - appPage.page.getByText("Business Line Advisory Services"), + appPage.page.getByText(workStream?.name?.en ?? ""), ).toBeVisible(); await expect( diff --git a/apps/playwright/tests/support-page.spec.ts b/apps/playwright/tests/support-page.spec.ts index bd4afe63f69..1d75be256fd 100644 --- a/apps/playwright/tests/support-page.spec.ts +++ b/apps/playwright/tests/support-page.spec.ts @@ -16,6 +16,21 @@ test.describe("Support page", () => { const accessibilityScanResults = await makeAxeBuilder().analyze(); expect(accessibilityScanResults.violations).toEqual([]); }); + test("populates from search param", async ({ page }) => { + await page.goto("/en/support?subject=bug&description=test"); + await expect( + page.getByRole("combobox", { name: /looking to/i }), + ).toHaveValue("bug"); + await expect(page.getByRole("textbox", { name: /details/i })).toHaveValue( + "test", + ); + }); + test("does not populate invalid subject param", async ({ page }) => { + await page.goto("/en/support?subject=invalid"); + await expect( + page.getByRole("combobox", { name: /looking to/i }), + ).toHaveValue(""); + }); }); test.describe("Support form", () => { test("send POST request to existing API endpoint", async ({ request }) => { diff --git a/apps/playwright/utils/pools.ts b/apps/playwright/utils/pools.ts index 70936cd7461..dadf4db14da 100644 --- a/apps/playwright/utils/pools.ts +++ b/apps/playwright/utils/pools.ts @@ -7,7 +7,6 @@ import { PoolOpportunityLength, PoolSkill, PoolSkillType, - PoolStream, PublishingGroup, SecurityStatus, SkillCategory, @@ -22,9 +21,9 @@ import { getCommunities } from "./communities"; import { getClassifications } from "./classification"; import { getDepartments } from "./departments"; import { getSkills } from "./skills"; +import { getWorkStreams } from "./workStreams"; const defaultPool: Partial = { - stream: PoolStream.BusinessAdvisoryServices, closingDate: `${FAR_FUTURE_DATE} 00:00:00`, yourImpact: { en: "test impact EN", @@ -222,6 +221,7 @@ interface CreateAndPublishPoolArgs { name?: LocalizedString; classificationId?: string; departmentId?: string; + workStreamId?: string; skillIds?: string[]; input?: UpdatePoolInput; } @@ -239,6 +239,7 @@ export const createAndPublishPool: GraphQLRequestFunc< communityId, classificationId, departmentId, + workStreamId, input, }, ) => { @@ -249,6 +250,12 @@ export const createAndPublishPool: GraphQLRequestFunc< classificationId, departmentId, }).then(async (pool) => { + let workStream = workStreamId; + if (!workStream) { + const workStreams = await getWorkStreams(ctx, {}); + workStream = workStreams[0].id; + } + await updatePool(ctx, { poolId: pool.id, pool: { @@ -258,6 +265,7 @@ export const createAndPublishPool: GraphQLRequestFunc< fr: `Playwright Test Pool FR ${Date.now().valueOf()}`, }, ...input, + workStream: { connect: workStream }, }, }); diff --git a/apps/playwright/utils/workStreams.ts b/apps/playwright/utils/workStreams.ts new file mode 100644 index 00000000000..df041e094a5 --- /dev/null +++ b/apps/playwright/utils/workStreams.ts @@ -0,0 +1,29 @@ +import { WorkStream } from "@gc-digital-talent/graphql"; + +import { GraphQLRequestFunc, GraphQLResponse } from "./graphql"; + +const Test_WorkStreamQueryDocument = /* GraphQL */ ` + query WorkStreams { + workStreams { + id + key + name { + en + fr + } + } + } +`; + +/** + * Get work streams + * + * Get all the work streams directly from the API. + */ +export const getWorkStreams: GraphQLRequestFunc = async (ctx) => { + return ctx + .post(Test_WorkStreamQueryDocument) + .then( + (res: GraphQLResponse<"workStreams", WorkStream[]>) => res.workStreams, + ); +}; diff --git a/apps/web/package.json b/apps/web/package.json index 811cbc8a82a..7f09cccc42c 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -51,16 +51,16 @@ "@gc-digital-talent/ui": "workspace:*", "@heroicons/react": "^2.2.0", "@microsoft/applicationinsights-web": "^3.3.4", - "@tanstack/react-table": "^8.20.5", + "@tanstack/react-table": "^8.20.6", "dataloader": "^2.2.3", "date-fns": "^3.6.0", - "framer-motion": "^11.14.1", - "graphql": "^16.9.0", + "framer-motion": "^11.15.0", + "graphql": "^16.10.0", "lodash": "^4.17.21", "react": "^18.3.1", "react-dom": "^18.2.0", "react-helmet-async": "^2.0.5", - "react-hook-form": "^7.54.0", + "react-hook-form": "^7.54.1", "react-intl": "^7.0.4", "react-router": "^7.0.2", "react-to-print": "^2.15.1", @@ -98,7 +98,7 @@ "ts-node": "^10.9.2", "tsconfig": "workspace:*", "typescript": "^5.7.2", - "vite": "^6.0.3", + "vite": "^6.0.4", "vite-plugin-compression2": "^1.3.3", "vite-plugin-html": "^3.2.2" } diff --git a/apps/web/src/components/ApplicationCard/ApplicationCard.tsx b/apps/web/src/components/ApplicationCard/ApplicationCard.tsx index d9575e71676..d91f16555ff 100644 --- a/apps/web/src/components/ApplicationCard/ApplicationCard.tsx +++ b/apps/web/src/components/ApplicationCard/ApplicationCard.tsx @@ -57,9 +57,9 @@ export const ApplicationCard_Fragment = graphql(/* GraphQL */ ` pool { id closingDate - stream { - value - label { + workStream { + id + name { en fr } @@ -130,13 +130,13 @@ const ApplicationCard = ({ application.submittedAt, ); const applicationTitle = getShortPoolTitleHtml(intl, { - stream: application.pool.stream, + workStream: application.pool.workStream, name: application.pool.name, publishingGroup: application.pool.publishingGroup, classification: application.pool.classification, }); const applicationTitleString = getShortPoolTitleLabel(intl, { - stream: application.pool.stream, + workStream: application.pool.workStream, name: application.pool.name, publishingGroup: application.pool.publishingGroup, classification: application.pool.classification, diff --git a/apps/web/src/components/AssessmentResultsTable/AssessmentResultsTable.tsx b/apps/web/src/components/AssessmentResultsTable/AssessmentResultsTable.tsx index 52c014ae87d..513c8983946 100644 --- a/apps/web/src/components/AssessmentResultsTable/AssessmentResultsTable.tsx +++ b/apps/web/src/components/AssessmentResultsTable/AssessmentResultsTable.tsx @@ -118,13 +118,6 @@ export const AssessmentResultsTable_Fragment = graphql(/* GraphQL */ ` fr } } - stream { - value - label { - en - fr - } - } name { en fr @@ -134,13 +127,6 @@ export const AssessmentResultsTable_Fragment = graphql(/* GraphQL */ ` group level } - stream { - value - label { - en - fr - } - } assessmentSteps { id title { diff --git a/apps/web/src/components/CandidateDialog/ChangeDateDialog.tsx b/apps/web/src/components/CandidateDialog/ChangeDateDialog.tsx index 57e7cc82d26..9070640da1b 100644 --- a/apps/web/src/components/CandidateDialog/ChangeDateDialog.tsx +++ b/apps/web/src/components/CandidateDialog/ChangeDateDialog.tsx @@ -37,9 +37,9 @@ export const ChangeDateDialog_PoolCandidateFragment = graphql(/* GraphQL */ ` expiryDate pool { id - stream { - value - label { + workStream { + id + name { en fr } @@ -177,7 +177,7 @@ const ChangeDateDialog = ({

-{" "} {getShortPoolTitleHtml(intl, { - stream: selectedCandidate.pool.stream, + workStream: selectedCandidate.pool.workStream, name: selectedCandidate.pool.name, publishingGroup: selectedCandidate.pool.publishingGroup, classification: selectedCandidate.pool.classification, diff --git a/apps/web/src/components/CandidateDialog/ChangeStatusDialog.tsx b/apps/web/src/components/CandidateDialog/ChangeStatusDialog.tsx index 9c8a923852a..de7f98b75a2 100644 --- a/apps/web/src/components/CandidateDialog/ChangeStatusDialog.tsx +++ b/apps/web/src/components/CandidateDialog/ChangeStatusDialog.tsx @@ -78,9 +78,9 @@ const ChangeStatusDialog_UserFragment = graphql(/* GraphQL */ ` group level } - stream { - value - label { + workStream { + id + name { en fr } @@ -123,9 +123,9 @@ export const ChangeStatusDialog_PoolCandidateFragment = graphql(/* GraphQL */ ` } pool { id - stream { - value - label { + workStream { + id + name { en fr } @@ -264,7 +264,7 @@ const ChangeStatusDialogForm = ({ {getShortPoolTitleHtml( intl, { - stream: r.poolCandidate.pool.stream, + workStream: r.poolCandidate.pool.workStream, name: r.poolCandidate.pool.name, publishingGroup: r.poolCandidate.pool.publishingGroup, classification: r.poolCandidate.pool.classification, @@ -412,7 +412,7 @@ const ChangeStatusDialog = ({ { status: getLocalizedName(selectedCandidate.status?.label, intl), poolName: getShortPoolTitleLabel(intl, { - stream: selectedCandidate.pool.stream, + workStream: selectedCandidate.pool.workStream, name: selectedCandidate.pool.name, publishingGroup: selectedCandidate.pool.publishingGroup, classification: selectedCandidate.pool.classification, @@ -453,7 +453,7 @@ const ChangeStatusDialog = ({

-{" "} {getShortPoolTitleHtml(intl, { - stream: selectedCandidate.pool.stream, + workStream: selectedCandidate.pool.workStream, name: selectedCandidate.pool.name, publishingGroup: selectedCandidate.pool.publishingGroup, classification: selectedCandidate.pool.classification, diff --git a/apps/web/src/components/ExperienceCard/ExperienceCard.tsx b/apps/web/src/components/ExperienceCard/ExperienceCard.tsx index febc5102170..bd9d1c6cd9b 100644 --- a/apps/web/src/components/ExperienceCard/ExperienceCard.tsx +++ b/apps/web/src/components/ExperienceCard/ExperienceCard.tsx @@ -15,7 +15,11 @@ import { useControllableState, } from "@gc-digital-talent/ui"; import { commonMessages, getLocalizedName } from "@gc-digital-talent/i18n"; -import { Skill } from "@gc-digital-talent/graphql"; +import { + EmploymentCategory, + Skill, + WorkExperienceGovEmployeeType, +} from "@gc-digital-talent/graphql"; import { AnyExperience } from "~/types/experience"; import { @@ -165,6 +169,53 @@ const ExperienceCard = ({ data-h2-color="base(black.light)" > {typeMessage} + {isWorkExperience(experience) && + experience.employmentCategory?.value === + EmploymentCategory.GovernmentOfCanada && ( + <> + + + {intl.formatMessage({ + defaultMessage: "Government of Canada", + id: "OKqOVT", + description: + "Label for goc employment category on work experience card metadata", + })} + + + )} + {isWorkExperience(experience) && + experience.employmentCategory?.value === + EmploymentCategory.GovernmentOfCanada && + experience.govEmploymentType?.value === + WorkExperienceGovEmployeeType.Contractor && ( + <> + + + {intl.formatMessage({ + defaultMessage: "Contractor", + id: "dpZ2B9", + description: + "Label for contractor employment type on work experience card metadata", + })} + + + )} + {isWorkExperience(experience) && + experience.employmentCategory?.value === + EmploymentCategory.CanadianArmedForces && ( + <> + + + {intl.formatMessage({ + defaultMessage: "Canadian Armed Forces", + id: "dBpcNA", + description: + "Label for caf employment category on work experience card metadata", + })} + + + )} {date && ( <> diff --git a/apps/web/src/components/ExperienceCard/WorkContent.tsx b/apps/web/src/components/ExperienceCard/WorkContent.tsx index 078a7fa08ae..6ab7b9d4751 100644 --- a/apps/web/src/components/ExperienceCard/WorkContent.tsx +++ b/apps/web/src/components/ExperienceCard/WorkContent.tsx @@ -1,28 +1,44 @@ import { useIntl } from "react-intl"; import { commonMessages } from "@gc-digital-talent/i18n"; -import { WorkExperience } from "@gc-digital-talent/graphql"; +import { EmploymentCategory, WorkExperience } from "@gc-digital-talent/graphql"; import { getExperienceFormLabels } from "~/utils/experienceUtils"; import ContentSection from "./ContentSection"; import { ContentProps } from "./types"; +import ExternalContent from "./WorkContent/ExternalContent"; +import CafContent from "./WorkContent/CafContent"; +import GovContent from "./WorkContent/GovContent"; const WorkContent = ({ - experience: { division }, + experience, headingLevel, }: ContentProps>) => { const intl = useIntl(); const experienceFormLabels = getExperienceFormLabels(intl); + const { division, employmentCategory } = experience; - return ( - - {division ?? intl.formatMessage(commonMessages.notAvailable)} - - ); + switch (employmentCategory?.value) { + case EmploymentCategory.ExternalOrganization: + return ( + + ); + case EmploymentCategory.GovernmentOfCanada: + return ; + case EmploymentCategory.CanadianArmedForces: + return ; + default: + return ( + + {division ?? intl.formatMessage(commonMessages.notAvailable)} + + ); + } }; export default WorkContent; diff --git a/apps/web/src/components/ExperienceCard/WorkContent/CafContent.tsx b/apps/web/src/components/ExperienceCard/WorkContent/CafContent.tsx new file mode 100644 index 00000000000..a3966432305 --- /dev/null +++ b/apps/web/src/components/ExperienceCard/WorkContent/CafContent.tsx @@ -0,0 +1,40 @@ +import { useIntl } from "react-intl"; + +import { getLocalizedName } from "@gc-digital-talent/i18n"; +import { WorkExperience } from "@gc-digital-talent/graphql"; +import { Separator } from "@gc-digital-talent/ui"; + +import { getExperienceFormLabels } from "~/utils/experienceUtils"; + +import ContentSection from "../ContentSection"; +import { ContentProps } from "../types"; + +const CafContent = ({ + experience: { cafEmploymentType, cafRank }, + headingLevel, +}: ContentProps>) => { + const intl = useIntl(); + const experienceFormLabels = getExperienceFormLabels(intl); + + return ( + <> + + {getLocalizedName(cafEmploymentType?.label, intl)} + + + + {getLocalizedName(cafRank?.label, intl)} + + + ); +}; + +export default CafContent; diff --git a/apps/web/src/components/ExperienceCard/WorkContent/ExternalContent.tsx b/apps/web/src/components/ExperienceCard/WorkContent/ExternalContent.tsx new file mode 100644 index 00000000000..dca72b5b7d2 --- /dev/null +++ b/apps/web/src/components/ExperienceCard/WorkContent/ExternalContent.tsx @@ -0,0 +1,52 @@ +import { useIntl } from "react-intl"; + +import { commonMessages, getLocalizedName } from "@gc-digital-talent/i18n"; +import { WorkExperience } from "@gc-digital-talent/graphql"; +import { Separator } from "@gc-digital-talent/ui"; + +import { getExperienceFormLabels } from "~/utils/experienceUtils"; + +import ContentSection from "../ContentSection"; +import { ContentProps } from "../types"; + +const ExternalContent = ({ + experience: { division, extSizeOfOrganization, extRoleSeniority }, + headingLevel, +}: ContentProps>) => { + const intl = useIntl(); + const experienceFormLabels = getExperienceFormLabels(intl); + + return ( + <> + + {division ?? intl.formatMessage(commonMessages.notAvailable)} + + +

+ + {getLocalizedName(extSizeOfOrganization?.label, intl)} + + + {getLocalizedName(extRoleSeniority?.label, intl)} + +
+ + ); +}; + +export default ExternalContent; diff --git a/apps/web/src/components/ExperienceCard/WorkContent/GovContent.tsx b/apps/web/src/components/ExperienceCard/WorkContent/GovContent.tsx new file mode 100644 index 00000000000..45514c8ffe1 --- /dev/null +++ b/apps/web/src/components/ExperienceCard/WorkContent/GovContent.tsx @@ -0,0 +1,191 @@ +import { useIntl } from "react-intl"; + +import { commonMessages, getLocalizedName } from "@gc-digital-talent/i18n"; +import { + GovContractorType, + WorkExperience, + WorkExperienceGovEmployeeType, +} from "@gc-digital-talent/graphql"; +import { Separator } from "@gc-digital-talent/ui"; + +import { getExperienceFormLabels } from "~/utils/experienceUtils"; + +import ContentSection from "../ContentSection"; +import { ContentProps } from "../types"; + +const GovContent = ({ + experience: { + division, + govEmploymentType, + classification, + govPositionType, + govContractorRoleSeniority, + govContractorType, + contractorFirmAgencyName, + }, + headingLevel, +}: ContentProps>) => { + const intl = useIntl(); + const experienceFormLabels = getExperienceFormLabels(intl); + + if (govEmploymentType?.value === WorkExperienceGovEmployeeType.Student) { + return ( + <> + + {division ?? intl.formatMessage(commonMessages.notAvailable)} + + + + {getLocalizedName(govEmploymentType.label, intl)} + + + ); + } else if ( + govEmploymentType?.value === WorkExperienceGovEmployeeType.Casual + ) { + return ( + <> + + {division ?? intl.formatMessage(commonMessages.notAvailable)} + + +
+ + {getLocalizedName(govEmploymentType.label, intl)} + + + {classification + ? `${classification.group}-0${classification.level}` + : intl.formatMessage(commonMessages.notAvailable)} + +
+ + ); + } else if ( + govEmploymentType?.value === WorkExperienceGovEmployeeType.Indeterminate || + govEmploymentType?.value === WorkExperienceGovEmployeeType.Term + ) { + return ( + <> + + {division ?? intl.formatMessage(commonMessages.notAvailable)} + + +
+ + {getLocalizedName(govEmploymentType.label, intl)} + + + {getLocalizedName(govPositionType?.label, intl)} + + + {classification + ? `${classification.group}-0${classification.level}` + : intl.formatMessage(commonMessages.notAvailable)} + +
+ + ); + } else if ( + govEmploymentType?.value === WorkExperienceGovEmployeeType.Contractor + ) { + return ( + <> + + {division ?? intl.formatMessage(commonMessages.notAvailable)} + + +
+ + {getLocalizedName(govEmploymentType.label, intl)} + + + {getLocalizedName(govContractorRoleSeniority?.label, intl)} + + + {getLocalizedName(govContractorType?.label, intl)} + +
+ {govContractorType?.value === GovContractorType.FirmOrAgency && ( + <> + + + {contractorFirmAgencyName ?? + intl.formatMessage(commonMessages.notAvailable)} + + + )} + + ); + } + + return null; +}; + +export default GovContent; diff --git a/apps/web/src/components/ExperienceFormFields/AdditionalDetails.tsx b/apps/web/src/components/ExperienceFormFields/AdditionalDetails.tsx index d2835ad2443..523b55c3caa 100644 --- a/apps/web/src/components/ExperienceFormFields/AdditionalDetails.tsx +++ b/apps/web/src/components/ExperienceFormFields/AdditionalDetails.tsx @@ -51,8 +51,8 @@ const AdditionalDetails = ({ experienceType }: AdditionalDetailsProps) => {

{intl.formatMessage({ defaultMessage: - "Describe key tasks, responsibilities, or other information you feel were crucial in making this experience important.", - id: "KKLx+Z", + "Describe key tasks, responsibilities, or other information you feel were crucial in making this experience important. Try to keep this field concise as you'll be able to provide more detailed information when linking skills to this experience.", + id: "yZ0kfQ", description: "Help text for the experience additional details field", })} diff --git a/apps/web/src/components/ExperienceFormFields/ExperienceDetails.tsx b/apps/web/src/components/ExperienceFormFields/ExperienceDetails.tsx index 4ddc0dd3361..ca7d48bcb08 100644 --- a/apps/web/src/components/ExperienceFormFields/ExperienceDetails.tsx +++ b/apps/web/src/components/ExperienceFormFields/ExperienceDetails.tsx @@ -10,7 +10,7 @@ import AwardFields from "./AwardFields"; import CommunityFields from "./CommunityFields"; import EducationFields from "./EducationFields"; import PersonalFields from "./PersonalFields"; -import WorkFields from "./WorkFields"; +import WorkFields from "./WorkFields/WorkFields"; import NullExperienceType from "./NullExperienceType"; interface ExperienceDetailsProps { diff --git a/apps/web/src/components/ExperienceFormFields/WorkFields.tsx b/apps/web/src/components/ExperienceFormFields/WorkFields.tsx deleted file mode 100644 index 40a39d1e29d..00000000000 --- a/apps/web/src/components/ExperienceFormFields/WorkFields.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import { useIntl } from "react-intl"; -import { useWatch } from "react-hook-form"; - -import { - Checkbox, - DATE_SEGMENT, - DateInput, - Input, -} from "@gc-digital-talent/forms"; -import { errorMessages } from "@gc-digital-talent/i18n"; -import { strToFormDate } from "@gc-digital-talent/date-helpers"; - -import { SubExperienceFormProps } from "~/types/experience"; - -const WorkFields = ({ labels }: SubExperienceFormProps) => { - const intl = useIntl(); - const todayDate = new Date(); - // to toggle whether End date is required, the state of the Current role checkbox must be monitored and have to adjust the form accordingly - const isCurrent = useWatch<{ currentRole: string }>({ name: "currentRole" }); - // ensuring end date isn't before the start date, using this as a minimum value - const startDate = useWatch<{ startDate: string }>({ name: "startDate" }); - - return ( -

-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- {/* conditionally render the end-date based off the state attached to the checkbox input */} - {!isCurrent && ( - - )} -
-
-
- ); -}; - -export default WorkFields; diff --git a/apps/web/src/components/ExperienceFormFields/WorkFields/CafFields.tsx b/apps/web/src/components/ExperienceFormFields/WorkFields/CafFields.tsx new file mode 100644 index 00000000000..c568db9e153 --- /dev/null +++ b/apps/web/src/components/ExperienceFormFields/WorkFields/CafFields.tsx @@ -0,0 +1,153 @@ +import { useIntl } from "react-intl"; +import { useWatch } from "react-hook-form"; +import { useQuery } from "urql"; + +import { + Checkbox, + DATE_SEGMENT, + DateInput, + localizedEnumToOptions, + RadioGroup, +} from "@gc-digital-talent/forms"; +import { errorMessages } from "@gc-digital-talent/i18n"; +import { strToFormDate } from "@gc-digital-talent/date-helpers"; +import { CafFieldsOptionsQuery, graphql } from "@gc-digital-talent/graphql"; +import { Loading } from "@gc-digital-talent/ui"; + +import { SubExperienceFormProps, WorkFormValues } from "~/types/experience"; + +const CafFieldsOptions_Query = graphql(/* GraphQL */ ` + query CafFieldsOptions { + cafEmploymentTypes: localizedEnumStrings(enumName: "CafEmploymentType") { + value + label { + en + fr + } + } + cafForces: localizedEnumStrings(enumName: "CafForce") { + value + label { + en + fr + } + } + cafRanks: localizedEnumStrings(enumName: "CafRank") { + value + label { + en + fr + } + } + } +`); + +const CafFields = ({ labels }: SubExperienceFormProps) => { + const intl = useIntl(); + const [{ data, fetching }] = useQuery({ + query: CafFieldsOptions_Query, + }); + + const todayDate = new Date(); + // to toggle whether End date is required, the state of the Current role checkbox must be monitored and have to adjust the form accordingly + const watchCurrentRole = useWatch({ name: "currentRole" }); + // ensuring end date isn't before the start date, using this as a minimum value + const watchStartDate = useWatch({ name: "startDate" }); + return ( + <> + {fetching ? ( +
+ +
+ ) : ( + <> +
+ +
+
+ +
+
+ +
+
+ +
+
+
+ +
+
+
+ {/* conditionally render the end-date based off the state attached to the checkbox input */} + {!watchCurrentRole && ( + + )} +
+ + )} + + ); +}; + +export default CafFields; diff --git a/apps/web/src/components/ExperienceFormFields/WorkFields/ExternalFields.tsx b/apps/web/src/components/ExperienceFormFields/WorkFields/ExternalFields.tsx new file mode 100644 index 00000000000..9f601a80d30 --- /dev/null +++ b/apps/web/src/components/ExperienceFormFields/WorkFields/ExternalFields.tsx @@ -0,0 +1,159 @@ +import { useIntl } from "react-intl"; +import { useWatch } from "react-hook-form"; +import { useQuery } from "urql"; + +import { + Checkbox, + DATE_SEGMENT, + DateInput, + Input, + localizedEnumToOptions, + RadioGroup, +} from "@gc-digital-talent/forms"; +import { errorMessages } from "@gc-digital-talent/i18n"; +import { strToFormDate } from "@gc-digital-talent/date-helpers"; +import { + ExternalWorkFieldOptionsQuery, + graphql, +} from "@gc-digital-talent/graphql"; +import { Loading } from "@gc-digital-talent/ui"; + +import { SubExperienceFormProps, WorkFormValues } from "~/types/experience"; + +const ExternalWorkFieldOptions_Query = graphql(/* GraphQL */ ` + query ExternalWorkFieldOptions { + extSizeOfOrganizations: localizedEnumStrings( + enumName: "ExternalSizeOfOrganization" + ) { + value + label { + en + fr + } + } + extRoleSeniorities: localizedEnumStrings( + enumName: "ExternalRoleSeniority" + ) { + value + label { + en + fr + } + } + } +`); + +const ExternalFields = ({ labels }: SubExperienceFormProps) => { + const intl = useIntl(); + const [{ data, fetching }] = useQuery({ + query: ExternalWorkFieldOptions_Query, + }); + + const todayDate = new Date(); + // to toggle whether End date is required, the state of the Current role checkbox must be monitored and have to adjust the form accordingly + const watchCurrentRole = useWatch({ name: "currentRole" }); + // ensuring end date isn't before the start date, using this as a minimum value + const watchStartDate = useWatch({ name: "startDate" }); + return ( + <> + {fetching ? ( +
+ +
+ ) : ( + <> +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+ +
+
+
+ {/* conditionally render the end-date based off the state attached to the checkbox input */} + {!watchCurrentRole && ( + + )} +
+ + )} + + ); +}; + +export default ExternalFields; diff --git a/apps/web/src/components/ExperienceFormFields/WorkFields/GovFields.tsx b/apps/web/src/components/ExperienceFormFields/WorkFields/GovFields.tsx new file mode 100644 index 00000000000..9a5fc905da4 --- /dev/null +++ b/apps/web/src/components/ExperienceFormFields/WorkFields/GovFields.tsx @@ -0,0 +1,456 @@ +import { useIntl } from "react-intl"; +import { useFormContext, useWatch } from "react-hook-form"; +import { useQuery } from "urql"; +import uniqBy from "lodash/uniqBy"; +import { useEffect } from "react"; + +import { + Checkbox, + DATE_SEGMENT, + DateInput, + Input, + localizedEnumToOptions, + RadioGroup, + Select, +} from "@gc-digital-talent/forms"; +import { + commonMessages, + errorMessages, + getLocalizedName, + uiMessages, +} from "@gc-digital-talent/i18n"; +import { strToFormDate } from "@gc-digital-talent/date-helpers"; +import { + GovContractorType, + GovFieldOptionsQuery, + GovPositionType, + graphql, + WorkExperienceGovEmployeeType, +} from "@gc-digital-talent/graphql"; +import { Loading } from "@gc-digital-talent/ui"; +import { unpackMaybes } from "@gc-digital-talent/helpers"; + +import { SubExperienceFormProps, WorkFormValues } from "~/types/experience"; +import { splitAndJoin } from "~/utils/nameUtils"; + +const GovFieldOptions_Query = graphql(/* GraphQL */ ` + query GovFieldOptions { + departments { + id + name { + en + fr + } + } + classifications { + id + name { + en + fr + } + group + level + } + govEmploymentTypes: localizedEnumStrings( + enumName: "WorkExperienceGovEmployeeType" + ) { + value + label { + en + fr + } + } + govPositionTypes: localizedEnumStrings(enumName: "GovPositionType") { + value + label { + en + fr + } + } + govContractorRoleSeniorities: localizedEnumStrings( + enumName: "GovContractorRoleSeniority" + ) { + value + label { + en + fr + } + } + govContractorTypes: localizedEnumStrings(enumName: "GovContractorType") { + value + label { + en + fr + } + } + } +`); + +const GovFields = ({ labels }: SubExperienceFormProps) => { + const intl = useIntl(); + const [{ data, fetching }] = useQuery({ + query: GovFieldOptions_Query, + }); + const { resetField } = useFormContext(); + + const todayDate = new Date(); + const watchStartDate = useWatch({ name: "startDate" }); + const watchCurrentRole = useWatch({ + name: "currentRole", + }); + const watchGroupSelection = useWatch({ + name: "classificationGroup", + }); + const watchGovEmploymentType = useWatch({ + name: "govEmploymentType", + }); + const watchGovPositionType = useWatch({ + name: "govPositionType", + }); + const watchGovContractorType = useWatch({ + name: "govContractorType", + }); + + // If the government employee type is "Term", + // then remove the "Substantive" option from the govPositionTypes + const allPositionTypes = localizedEnumToOptions(data?.govPositionTypes, intl); + const conditionalPositionTypes = + watchGovEmploymentType === WorkExperienceGovEmployeeType.Term + ? allPositionTypes.filter( + (positionType) => + positionType.value !== String(GovPositionType.Substantive), + ) + : allPositionTypes; + + const departmentOptions = unpackMaybes(data?.departments).map( + ({ id, name }) => ({ + value: id, + label: getLocalizedName(name, intl), + }), + ); + + // Consolidate James's classification-> group and level form logic + const classifications = unpackMaybes(data?.classifications); + + const classGroupsWithDupes: { + label: string; + ariaLabel: string; + }[] = classifications.map((classification) => { + return { + label: + classification.group || + intl.formatMessage({ + defaultMessage: "Error: classification group not found.", + id: "YA/7nb", + description: "Error message if classification group is not defined.", + }), + ariaLabel: `${getLocalizedName(classification.name, intl)} ${splitAndJoin( + classification.group, + )}`, + }; + }); + const noDupes = uniqBy(classGroupsWithDupes, "label"); + const groupOptions = noDupes.map(({ label, ariaLabel }) => { + return { + value: label, + label, + ariaLabel, + }; + }); + + // generate classification levels from the selected group + const levelOptions = classifications + .filter((x) => x.group === watchGroupSelection) + .map((iterator) => { + return { + value: iterator.id.toString(), // change the value to id for the query + label: iterator.level.toString(), + }; + }); + + /** + * Reset classification level when group changes + * because level options change + */ + useEffect(() => { + resetField("classificationLevel", { + keepDirty: false, + }); + }, [resetField, watchGroupSelection]); + + const isIndeterminate = + watchGovEmploymentType === WorkExperienceGovEmployeeType.Indeterminate; + const indeterminateActing = + isIndeterminate && watchGovPositionType === GovPositionType.Acting; + const indeterminateAssignment = + isIndeterminate && watchGovPositionType === GovPositionType.Assignment; + const indeterminateSecondment = + isIndeterminate && watchGovPositionType === GovPositionType.Secondment; + + const expectedEndDate = + watchCurrentRole && + (watchGovEmploymentType === WorkExperienceGovEmployeeType.Student || + watchGovEmploymentType === WorkExperienceGovEmployeeType.Casual || + watchGovEmploymentType === WorkExperienceGovEmployeeType.Term || + indeterminateActing || + indeterminateAssignment || + indeterminateSecondment); + + /** + * Reset classification group and level + * when the employment type changes to casual or contract + */ + useEffect(() => { + const resetDirtyField = (name: keyof WorkFormValues) => { + resetField(name, { + keepDirty: false, + }); + }; + + if ( + watchGovEmploymentType === WorkExperienceGovEmployeeType.Student || + watchGovEmploymentType === WorkExperienceGovEmployeeType.Contractor + ) { + resetDirtyField("classificationGroup"); + resetDirtyField("classificationLevel"); + } + + if (watchGovEmploymentType) { + resetDirtyField("govPositionType"); + } + + if (watchGovEmploymentType !== WorkExperienceGovEmployeeType.Contractor) { + resetDirtyField("govContractorRoleSeniority"); + resetDirtyField("govContractorType"); + } + + if ( + watchGovContractorType === GovContractorType.SelfEmployed || + watchGovEmploymentType !== WorkExperienceGovEmployeeType.Contractor + ) { + resetField("contractorFirmAgencyName", { + keepDirty: false, + defaultValue: undefined, + }); + } + }, [resetField, watchGovEmploymentType, watchGovContractorType]); + + return ( + <> + {fetching ? ( +
+ +
+ ) : ( + <> +
+ +
+
+ +
+ {(watchGovEmploymentType === + WorkExperienceGovEmployeeType.Indeterminate || + watchGovEmploymentType === WorkExperienceGovEmployeeType.Term) && ( +
+ +
+ )} + {watchGovEmploymentType === + WorkExperienceGovEmployeeType.Contractor && ( + <> +
+ +
+
+ +
+ + )} + {watchGovContractorType === GovContractorType.FirmOrAgency && ( +
+ +
+ )} + {(watchGovEmploymentType === WorkExperienceGovEmployeeType.Casual || + watchGovEmploymentType === + WorkExperienceGovEmployeeType.Indeterminate || + watchGovEmploymentType === WorkExperienceGovEmployeeType.Term) && ( + <> +
+ +
+ + )} +
+ +
+
+
+ +
+
+
+ {expectedEndDate ? ( + + ) : ( + <> + {!watchCurrentRole && ( + + )} + + )} +
+ + )} + + ); +}; + +export default GovFields; diff --git a/apps/web/src/components/ExperienceFormFields/WorkFields/WorkFields.tsx b/apps/web/src/components/ExperienceFormFields/WorkFields/WorkFields.tsx new file mode 100644 index 00000000000..af0083262f6 --- /dev/null +++ b/apps/web/src/components/ExperienceFormFields/WorkFields/WorkFields.tsx @@ -0,0 +1,194 @@ +import { useIntl, defineMessage, MessageDescriptor } from "react-intl"; +import { useQuery } from "urql"; +import { useFormContext, useWatch } from "react-hook-form"; +import { useEffect } from "react"; + +import { + FieldLabels, + Input, + Radio, + RadioGroup, +} from "@gc-digital-talent/forms"; +import { errorMessages, getLocalizedName } from "@gc-digital-talent/i18n"; +import { Loading } from "@gc-digital-talent/ui"; +import { + EmploymentCategory, + graphql, + WorkFieldOptionsQuery, +} from "@gc-digital-talent/graphql"; +import { unpackMaybes } from "@gc-digital-talent/helpers"; + +import { SubExperienceFormProps, WorkFormValues } from "~/types/experience"; + +import CafFields from "./CafFields"; +import ExternalFields from "./ExternalFields"; +import GovFields from "./GovFields"; + +const WorkFieldOptions_Query = graphql(/* GraphQL */ ` + query WorkFieldOptions { + employmentCategoryTypes: localizedEnumStrings( + enumName: "EmploymentCategory" + ) { + value + label { + en + fr + } + } + } +`); + +const EmploymentCategoryFields = ({ + employmentCategory, + labels, +}: { + employmentCategory: EmploymentCategory; + labels: FieldLabels; +}) => { + switch (employmentCategory) { + case EmploymentCategory.CanadianArmedForces: + return ; + case EmploymentCategory.ExternalOrganization: + return ; + case EmploymentCategory.GovernmentOfCanada: + return ; + default: + return null; + } +}; + +const employmentCategoryDescriptions: Record< + EmploymentCategory, + MessageDescriptor +> = { + EXTERNAL_ORGANIZATION: defineMessage({ + defaultMessage: + "Select this option if the employment had no affiliation with the Government of Canada.", + id: "0MakGC", + description: + "Description for the external employment category option in work experience", + }), + GOVERNMENT_OF_CANADA: defineMessage({ + defaultMessage: + "Select this option if the employment was with a Government of Canada department, agency, crown corporation, or if you were a contractor working with one of these organizations.", + id: "nmx1ym", + description: + "Description for the goc employment category option in work experience", + }), + CANADIAN_ARMED_FORCES: defineMessage({ + defaultMessage: + "Select this option if the employment was with Canadian Army, the Royal Canadian Air Force, or the Royal Canadian Navy, either as regular force, or reserve force.", + id: "uZuEHk", + description: + "Description for the caf employment category option in work experience", + }), +}; + +const WorkFields = ({ labels }: SubExperienceFormProps) => { + const intl = useIntl(); + const [{ data, fetching }] = useQuery({ + query: WorkFieldOptions_Query, + }); + + const { resetField, formState } = useFormContext(); + + const watchEmploymentCategory = useWatch<{ + employmentCategory: EmploymentCategory; + }>({ + name: "employmentCategory", + }); + + const employmentCategories: Radio[] = unpackMaybes( + data?.employmentCategoryTypes, + ).map(({ value, label }) => { + const contentBelow = + employmentCategoryDescriptions[value as EmploymentCategory]; + return { + label: getLocalizedName(label, intl), + value, + contentBelow: intl.formatMessage(contentBelow), + }; + }); + + /** + * Reset all fields when employmentCategory field is changed + */ + useEffect(() => { + const resetDirtyField = (name: keyof WorkFormValues) => { + resetField(name, { keepDirty: false, defaultValue: null }); + }; + + if (formState.dirtyFields.employmentCategory) { + resetDirtyField("team"); // both external and goc + + // external fields + resetDirtyField("organization"); + resetDirtyField("extSizeOfOrganization"); + resetDirtyField("extRoleSeniority"); + + // goc fields + resetDirtyField("department"); + resetDirtyField("govEmploymentType"); + resetDirtyField("govPositionType"); + resetDirtyField("govContractorRoleSeniority"); + resetDirtyField("govContractorType"); + resetDirtyField("contractorFirmAgencyName"); + resetDirtyField("classificationGroup"); + resetDirtyField("classificationLevel"); + + // caf fields + resetDirtyField("cafEmploymentType"); + resetDirtyField("cafForce"); + resetDirtyField("cafRank"); + + // all categories + resetDirtyField("startDate"); + resetDirtyField("currentRole"); + resetDirtyField("endDate"); + } + }, [formState.dirtyFields, watchEmploymentCategory, resetField]); + + return ( +
+ {fetching ? ( + + ) : ( +
+
+
+ +
+
+ +
+ +
+
+ )} +
+ ); +}; + +export default WorkFields; diff --git a/apps/web/src/components/PoolCandidatesTable/PoolCandidatesTable.tsx b/apps/web/src/components/PoolCandidatesTable/PoolCandidatesTable.tsx index f7540789ed9..d675be66be6 100644 --- a/apps/web/src/components/PoolCandidatesTable/PoolCandidatesTable.tsx +++ b/apps/web/src/components/PoolCandidatesTable/PoolCandidatesTable.tsx @@ -195,9 +195,9 @@ const CandidatesTableCandidatesPaginated_Query = graphql(/* GraphQL */ ` group level } - stream { - value - label { + workStream { + id + name { en fr } @@ -718,7 +718,7 @@ const PoolCandidatesTable = ({ columnHelper.accessor( ({ poolCandidate: { pool } }) => getFullPoolTitleLabel(intl, { - stream: pool.stream, + workStream: pool.workStream, name: pool.name, publishingGroup: pool.publishingGroup, classification: pool.classification, @@ -737,7 +737,7 @@ const PoolCandidatesTable = ({ processCell( { id: pool.id, - stream: pool.stream, + workStream: pool.workStream, name: pool.name, publishingGroup: pool.publishingGroup, classification: pool.classification, diff --git a/apps/web/src/components/PoolCandidatesTable/SkillMatchDialog.tsx b/apps/web/src/components/PoolCandidatesTable/SkillMatchDialog.tsx index 77b4e982cd9..2edbe42145a 100644 --- a/apps/web/src/components/PoolCandidatesTable/SkillMatchDialog.tsx +++ b/apps/web/src/components/PoolCandidatesTable/SkillMatchDialog.tsx @@ -100,6 +100,90 @@ const SkillMatchDialog_Query = graphql(/* GraphQL */ ` division startDate endDate + employmentCategory { + value + label { + en + fr + } + } + extSizeOfOrganization { + value + label { + en + fr + } + } + extRoleSeniority { + value + label { + en + fr + } + } + govEmploymentType { + value + label { + en + fr + } + } + govPositionType { + value + label { + en + fr + } + } + govContractorRoleSeniority { + value + label { + en + fr + } + } + govContractorType { + value + label { + en + fr + } + } + contractorFirmAgencyName + cafEmploymentType { + value + label { + en + fr + } + } + cafForce { + value + label { + en + fr + } + } + cafRank { + value + label { + en + fr + } + } + classification { + id + group + level + } + department { + id + departmentNumber + name { + en + fr + } + } } } } diff --git a/apps/web/src/components/PoolCandidatesTable/helpers.tsx b/apps/web/src/components/PoolCandidatesTable/helpers.tsx index 7a0b8c839d3..3a894b65fba 100644 --- a/apps/web/src/components/PoolCandidatesTable/helpers.tsx +++ b/apps/web/src/components/PoolCandidatesTable/helpers.tsx @@ -13,7 +13,6 @@ import { parseDateTimeUtc } from "@gc-digital-talent/date-helpers"; import { Link, Chip, Spoiler } from "@gc-digital-talent/ui"; import { CandidateExpiryFilter, - PoolStream, PublishingGroup, Maybe, Pool, @@ -100,14 +99,14 @@ export const candidateNameCell = ( }; export const processCell = ( - pool: Pick & { + pool: Pick & { classification?: Maybe>; }, paths: ReturnType, intl: IntlShape, ) => { const poolName = getFullPoolTitleLabel(intl, { - stream: pool.stream, + workStream: pool.workStream, name: pool.name, publishingGroup: pool.publishingGroup, classification: pool.classification, @@ -380,7 +379,10 @@ export function transformPoolCandidateSearchInputToFormValues( input?.appliedClassifications ?.filter(notEmpty) .map((c) => `${c.group}-${c.level}`) ?? [], - stream: input?.applicantFilter?.qualifiedStreams?.filter(notEmpty) ?? [], + stream: + input?.applicantFilter?.workStreams + ?.filter(notEmpty) + .map(({ id }) => id) ?? [], languageAbility: input?.applicantFilter?.languageAbility ?? "", workRegion: input?.applicantFilter?.locationPreferences?.filter(notEmpty) ?? [], @@ -427,7 +429,7 @@ export function transformFormValuesToFilterState( languageAbility: data.languageAbility ? stringToEnumLanguage(data.languageAbility) : undefined, - qualifiedStreams: data.stream as PoolStream[], + workStreams: data.stream.map((id) => ({ id })), operationalRequirements: data.operationalRequirement .map((requirement) => { return stringToEnumOperational(requirement); diff --git a/apps/web/src/components/PoolCard/PoolCard.tsx b/apps/web/src/components/PoolCard/PoolCard.tsx index 1a503e0f798..6d2eb882cd4 100644 --- a/apps/web/src/components/PoolCard/PoolCard.tsx +++ b/apps/web/src/components/PoolCard/PoolCard.tsx @@ -41,9 +41,9 @@ import IconLabel from "./IconLabel"; export const PoolCard_Fragment = graphql(/* GraphQL */ ` fragment PoolCard on Pool { id - stream { - value - label { + workStream { + id + name { en fr } @@ -258,7 +258,7 @@ const PoolCard = ({ poolQuery, headingLevel = "h3" }: PoolCardProps) => { data-h2-min-height="base(x4.5) p-tablet(auto)" > {getShortPoolTitleHtml(intl, { - stream: pool.stream, + workStream: pool.workStream, name: pool.name, publishingGroup: pool.publishingGroup, classification: pool.classification, diff --git a/apps/web/src/components/PoolFilterInput/usePoolFilterOptions.ts b/apps/web/src/components/PoolFilterInput/usePoolFilterOptions.ts index 191cdbc00ce..c53b1f51cb8 100644 --- a/apps/web/src/components/PoolFilterInput/usePoolFilterOptions.ts +++ b/apps/web/src/components/PoolFilterInput/usePoolFilterOptions.ts @@ -32,9 +32,9 @@ const PoolFilter_Query = graphql(/* GraphQL */ ` fr } } - stream { - value - label { + workStream { + id + name { en fr } @@ -85,7 +85,7 @@ const usePoolFilterOptions = ( pools.map((pool) => ({ value: pool.id, label: getShortPoolTitleLabel(intl, { - stream: pool.stream, + workStream: pool.workStream, name: pool.name, publishingGroup: pool.publishingGroup, classification: pool.classification, diff --git a/apps/web/src/components/PoolStatusTable/PoolStatusTable.tsx b/apps/web/src/components/PoolStatusTable/PoolStatusTable.tsx index 51ba3363e58..2bdc1044ebb 100644 --- a/apps/web/src/components/PoolStatusTable/PoolStatusTable.tsx +++ b/apps/web/src/components/PoolStatusTable/PoolStatusTable.tsx @@ -65,9 +65,9 @@ const PoolStatusTable_Fragment = graphql(/* GraphQL */ ` group level } - stream { - value - label { + workStream { + id + name { en fr } @@ -105,7 +105,7 @@ const PoolStatusTable = ({ userQuery }: PoolStatusTableProps) => { columnHelper.accessor( (row) => getShortPoolTitleLabel(intl, { - stream: row.pool.stream, + workStream: row.pool.workStream, name: row.pool.name, publishingGroup: row.pool.publishingGroup, classification: row.pool.classification, @@ -195,7 +195,7 @@ const PoolStatusTable = ({ userQuery }: PoolStatusTableProps) => { }, ), columnHelper.accessor( - ({ pool: { stream } }) => getLocalizedName(stream?.label, intl), + ({ pool: { workStream } }) => getLocalizedName(workStream?.name, intl), { id: "application", enableHiding: false, diff --git a/apps/web/src/components/PoolStatusTable/types.ts b/apps/web/src/components/PoolStatusTable/types.ts index 4cc0337697e..22fab002a21 100644 --- a/apps/web/src/components/PoolStatusTable/types.ts +++ b/apps/web/src/components/PoolStatusTable/types.ts @@ -24,9 +24,9 @@ const PoolStatusTable_PoolCandidateFragment = graphql(/* GraphQL */ ` fr } } - stream { - value - label { + workStream { + id + name { en fr } diff --git a/apps/web/src/components/RecruitmentAvailabilityDialog/RecruitmentAvailabilityDialog.tsx b/apps/web/src/components/RecruitmentAvailabilityDialog/RecruitmentAvailabilityDialog.tsx index 27ab06e71e0..bf6b126d2c8 100644 --- a/apps/web/src/components/RecruitmentAvailabilityDialog/RecruitmentAvailabilityDialog.tsx +++ b/apps/web/src/components/RecruitmentAvailabilityDialog/RecruitmentAvailabilityDialog.tsx @@ -32,9 +32,9 @@ const RecruitmentAvailabilityDialog_Fragment = graphql(/* GraphQL */ ` suspendedAt pool { id - stream { - value - label { + workStream { + id + name { en fr } @@ -77,7 +77,7 @@ const RecruitmentAvailabilityDialog = ({ const [isOpen, setIsOpen] = useState(false); const isSuspended = !!candidate.suspendedAt; const title = poolTitle(intl, { - stream: candidate.pool.stream, + workStream: candidate.pool.workStream, name: candidate.pool.name, publishingGroup: candidate.pool.publishingGroup, classification: candidate.pool.classification, diff --git a/apps/web/src/components/Router.tsx b/apps/web/src/components/Router.tsx index 7136dabd25b..f8154d338c7 100644 --- a/apps/web/src/components/Router.tsx +++ b/apps/web/src/components/Router.tsx @@ -210,6 +210,13 @@ const createRoute = (locale: Locales) => "../pages/ProfileAndApplicationsPage/ProfileAndApplicationsPage" ), }, + // { + // path: "dashboard-test", + // lazy: () => + // import( + // "../pages/ApplicantDashboardPage/ApplicantDashboardPage" + // ), + // }, { path: "settings", lazy: () => diff --git a/apps/web/src/components/SearchRequestFilters/SearchRequestFilters.tsx b/apps/web/src/components/SearchRequestFilters/SearchRequestFilters.tsx index c1ad42b14c5..afe349201ad 100644 --- a/apps/web/src/components/SearchRequestFilters/SearchRequestFilters.tsx +++ b/apps/web/src/components/SearchRequestFilters/SearchRequestFilters.tsx @@ -111,7 +111,7 @@ const ApplicantFilters = ({ ).map((label) => getLocalizedName(label, intl)); const streams = unpackMaybes( - applicantFilter?.qualifiedStreams?.flatMap((stream) => stream?.label), + applicantFilter?.workStreams?.flatMap((stream) => stream?.name), ).map((label) => getLocalizedName(label, intl)); const communityName: string = @@ -142,7 +142,7 @@ const ApplicantFilters = ({ applicantFilter ? applicantFilter?.pools?.filter(notEmpty)?.map((pool) => getShortPoolTitleHtml(intl, { - stream: pool.stream, + workStream: pool.workStream, name: pool.name, publishingGroup: pool.publishingGroup, classification: pool.classification, @@ -277,8 +277,8 @@ const SearchRequestFilters = ({ ? poolCandidateFilter?.pools?.filter(notEmpty) : []; - const streams = pools?.map((pool) => - pool.stream?.label ? getLocalizedName(pool.stream.label, intl) : "", + const streams = pools?.map(({ workStream }) => + getLocalizedName(workStream?.name, intl, true), ); // eslint-disable-next-line deprecation/deprecation @@ -373,7 +373,7 @@ const SearchRequestFilters = ({ pools ? pools.map((pool) => getShortPoolTitleHtml(intl, { - stream: pool.stream, + workStream: pool.workStream, name: pool.name, publishingGroup: pool.publishingGroup, classification: pool.classification, diff --git a/apps/web/src/components/SearchRequestTable/SearchRequestTable.tsx b/apps/web/src/components/SearchRequestTable/SearchRequestTable.tsx index 36eeaa89a89..ea2a403af66 100644 --- a/apps/web/src/components/SearchRequestTable/SearchRequestTable.tsx +++ b/apps/web/src/components/SearchRequestTable/SearchRequestTable.tsx @@ -91,7 +91,7 @@ const transformSearchRequestInput = ( status: filterState?.status, departments: filterState?.departments, classifications: filterState?.classifications, - streams: filterState?.streams, + workStreams: filterState?.workStreams, }; }; @@ -125,9 +125,9 @@ const SearchRequestTable_Query = graphql(/* GraphQL */ ` group level } - qualifiedStreams { - value - label { + workStreams { + id + name { en fr } @@ -270,8 +270,8 @@ const SearchRequestTable = ({ title }: SearchRequestTableProps) => { columnHelper.accessor( ({ applicantFilter }) => unpackMaybes( - applicantFilter?.qualifiedStreams?.map((stream) => - getLocalizedName(stream?.label, intl), + applicantFilter?.workStreams?.map((workStream) => + getLocalizedName(workStream?.name, intl), ), ).join(","), { @@ -287,8 +287,8 @@ const SearchRequestTable = ({ title }: SearchRequestTableProps) => { cells.commaList({ list: unpackMaybes( - applicantFilter?.qualifiedStreams?.map((stream) => - getLocalizedName(stream?.label, intl, true), + applicantFilter?.workStreams?.map((workStream) => + getLocalizedName(workStream?.name, intl, true), ), ) ?? [], }), diff --git a/apps/web/src/components/SearchRequestTable/components/SearchRequestFilterDialog.tsx b/apps/web/src/components/SearchRequestTable/components/SearchRequestFilterDialog.tsx index 9afd347ec0b..7e0e8c7f665 100644 --- a/apps/web/src/components/SearchRequestTable/components/SearchRequestFilterDialog.tsx +++ b/apps/web/src/components/SearchRequestTable/components/SearchRequestFilterDialog.tsx @@ -53,9 +53,9 @@ const SearchRequestFilterData_Query = graphql(/* GraphQL */ ` fr } } - streams: localizedEnumStrings(enumName: "PoolStream") { - value - label { + workStreams { + id + name { en fr } @@ -133,11 +133,14 @@ const SearchRequestFilterDialog = ({ }))} /> ({ + value: workStream.id, + label: getLocalizedName(workStream?.name, intl), + }))} /> diff --git a/apps/web/src/components/SearchRequestTable/components/utils.tsx b/apps/web/src/components/SearchRequestTable/components/utils.tsx index c6cd54a68a4..230a4860cf4 100644 --- a/apps/web/src/components/SearchRequestTable/components/utils.tsx +++ b/apps/web/src/components/SearchRequestTable/components/utils.tsx @@ -7,16 +7,13 @@ import { SortOrder, } from "@gc-digital-talent/graphql"; -import { - stringToEnumRequestStatus, - stringToEnumStream, -} from "~/utils/requestUtils"; +import { stringToEnumRequestStatus } from "~/utils/requestUtils"; export interface FormValues { status?: string[]; departments?: string[]; classifications?: string[]; - streams?: string[]; + workStreams?: string[]; } export function transformFormValuesToSearchRequestFilterInput( @@ -30,8 +27,8 @@ export function transformFormValuesToSearchRequestFilterInput( classifications: data.classifications?.length ? data.classifications : undefined, - streams: data.streams?.length - ? data.streams.map(stringToEnumStream).filter(notEmpty) + workStreams: data.workStreams?.length + ? data.workStreams.filter(notEmpty) : undefined, }; } @@ -69,6 +66,6 @@ export function transformSearchRequestFilterInputToFormValues( status: input?.status?.filter(notEmpty) ?? [], departments: input?.departments?.filter(notEmpty) ?? [], classifications: input?.classifications?.filter(notEmpty) ?? [], - streams: input?.streams?.filter(notEmpty) ?? [], + workStreams: input?.workStreams?.filter(notEmpty) ?? [], }; } diff --git a/apps/web/src/components/SkillBrowser/utils.ts b/apps/web/src/components/SkillBrowser/utils.ts index 34a3abb46c5..2203c2dc37c 100644 --- a/apps/web/src/components/SkillBrowser/utils.ts +++ b/apps/web/src/components/SkillBrowser/utils.ts @@ -79,8 +79,8 @@ export const getSkillBrowserDialogMessages: GetSkillBrowserDialogMessages = ({ return { ...defaults, trigger: intl.formatMessage({ - defaultMessage: "Add a new skill", - id: "ZYqWBR", + defaultMessage: "Add skill", + id: "RSUgO3", description: "Button text to open the skill dialog and add a skill", }), title: intl.formatMessage({ diff --git a/apps/web/src/lang/__snapshots__/lang.test.ts.snap b/apps/web/src/lang/__snapshots__/lang.test.ts.snap index c355564e1e3..f15a9a99f1c 100644 --- a/apps/web/src/lang/__snapshots__/lang.test.ts.snap +++ b/apps/web/src/lang/__snapshots__/lang.test.ts.snap @@ -45,10 +45,10 @@ exports[`message files should have no changes to duplicate strings 1`] = ` ] }, { - "en": "Create a community", + "en": "Add member", "fr": [ - "Créez une collectivité", - "Créer une collectivité" + "Ajouter un membre", + "Ajoutez un membre" ] }, { @@ -87,17 +87,24 @@ exports[`message files should have no changes to duplicate strings 1`] = ` ] }, { - "en": "Add team role", + "en": "Create training opportunity", "fr": [ - "Ajouter un rôle dans l'équipe", - "Ajoutez un rôle dans l'équipe" + "Créez une possibilité de formation", + "Créez la possibilité de formation" ] }, { - "en": "Create a training opportunity", + "en": "Create community", "fr": [ - "Créez une possibilité de formation", - "Créer une possibilité de formation" + "Créez une collectivité", + "Créer une collectivité" + ] + }, + { + "en": "Add team role", + "fr": [ + "Ajouter un rôle dans l'équipe", + "Ajoutez un rôle dans l'équipe" ] }, { @@ -138,10 +145,17 @@ exports[`message files should have no changes to duplicate strings 1`] = ` { "en": "Create skill family", "fr": [ - "Créer un groupe de compétences", + "Créez un groupe de compétences", "Créez le groupe de compétences" ] }, + { + "en": "Create process", + "fr": [ + "Créer un processus", + "Créez un processus" + ] + }, { "en": "Remove from community", "fr": [ diff --git a/apps/web/src/lang/fr.json b/apps/web/src/lang/fr.json index bb404b123a2..cc87a85da9b 100644 --- a/apps/web/src/lang/fr.json +++ b/apps/web/src/lang/fr.json @@ -119,10 +119,6 @@ "defaultMessage": "Voir les critères d’admissibilité", "description": "Button text for program eligibility criteria" }, - "+e2nr6": { - "defaultMessage": "Ajouter un nouveau membre", - "description": "Label for the add member to team form" - }, "+fIw4g": { "defaultMessage": "Modifier ces renseignements pour {title}", "description": "Text label for button to edit employment equity category in profile." @@ -420,7 +416,7 @@ "description": "Third paragraph for pool closing date dialog" }, "07sCDh": { - "defaultMessage": "Utilisez le bouton « Créer un processus » pour commencer.", + "defaultMessage": "Utilisez le bouton « Créez un processus » pour commencer.", "description": "Instructions for adding a process item." }, "08IbRz": { @@ -443,6 +439,10 @@ "defaultMessage": "Deux plumes attachées l’une à l’autre.", "description": "Indigenous Apprenticeship feathers image text alternative" }, + "0Dp1N4": { + "defaultMessage": "Type de poste", + "description": "Label for the position type radio group" + }, "0E9hiS": { "defaultMessage": "Groupes de compétences", "description": "Title for skill families" @@ -479,6 +479,10 @@ "defaultMessage": "De la même manière que vous avez sélectionné des éléments de votre parcours professionnel pour confirmer les exigences en matière d’expérience et d’études, nous vous demanderons de décrire une ou plusieurs expériences de votre parcours professionnel au cours desquelles vous avez activement utilisé la compétence requise.", "description": "Application step for skill requirements, introduction, description, paragraph two" }, + "0MakGC": { + "defaultMessage": "Sélectionnez cette option si l'emploi n'avait aucun lien avec le gouvernement du Canada.", + "description": "Description for the external employment category option in work experience" + }, "0NbdGD": { "defaultMessage": "Erreur : Échec de la suppression de la compétence", "description": "Message displayed to user after skill fails to be deleted." @@ -552,7 +556,7 @@ "description": "Simplified status label for a complete process advertisement or assessment" }, "0jwdac": { - "defaultMessage": "Utilisez le bouton « Créer une compétence » pour commencer.", + "defaultMessage": "Utilisez le bouton « Créez une compétence » pour commencer.", "description": "Instructions for adding a skill item." }, "0k6j4V": { @@ -567,6 +571,10 @@ "defaultMessage": "Compétences techniques", "description": "Title for the technical skill rank card" }, + "0qwyH4": { + "defaultMessage": "Date de fin prévue", + "description": "Label displayed on an Experience form for expected end date input" + }, "0w59dG": { "defaultMessage": "Votre parcours professionnel", "description": "Heading for career timeline section of the application review page." @@ -699,6 +707,10 @@ "defaultMessage": "Signature", "description": "Title for the signature snapshot section" }, + "1b+6V1": { + "defaultMessage": "{role} à {group}", + "description": "Role with group" + }, "1bWLa3": { "defaultMessage": "Compétences que le candidat aimerait améliorer", "description": "Heading for a users skills they would like to improve" @@ -743,8 +755,12 @@ "defaultMessage": "Groupes de compétences (anglais)", "description": "Title for skill families in English" }, + "1syFdp": { + "defaultMessage": "{role} à {group}", + "description": "Role with group, HTML" + }, "1xI8uo": { - "defaultMessage": "Utilisez le bouton « Ajoutez un rôle dans l’équipe » pour commencer.", + "defaultMessage": "Utilisez le bouton « Ajoutez un rôle individuel » pour commencer.", "description": "Instructions for adding a role to a user." }, "2/fjEP": { @@ -812,7 +828,7 @@ "description": "Subject for email to gain hiring experience" }, "2Oubfe": { - "defaultMessage": "Type d’emploi", + "defaultMessage": "Type d'emploi", "description": "Label for applicant's employment type" }, "2QDT5C": { @@ -904,7 +920,7 @@ "description": "Paragraph 3, importance of self-declaration" }, "2m5USi": { - "defaultMessage": "Utilisez le bouton « Modifier » pour commencer. ", + "defaultMessage": "Utilisez le bouton « Modifiez » pour commencer. ", "description": "Null message on sections for edit pool page." }, "2n0e2i": { @@ -971,6 +987,10 @@ "defaultMessage": "Changer votre disponibilité", "description": "Button text to open form to change availability in a generic recruitment" }, + "34NvoS": { + "defaultMessage": "L'ancienneté du poste", + "description": "Label for the seniority of the role radio group" + }, "37mBAU": { "defaultMessage": "Faites croître votre carrière et trouvez des talents pour votre équipe.", "description": "Subtitle for the manager homepage" @@ -1295,6 +1315,10 @@ "defaultMessage": "Les renseignements que vous fournissez peuvent également être utilisés à des fins statistiques et de recherche, et ils peuvent être communiqués à laDirection des enquêtes de la Commission de la fonction publique au besoin.", "description": "Paragraph for privacy policy page" }, + "4fV+wX": { + "defaultMessage": "Catégorie de grade", + "description": "Label for the rank category radio group" + }, "4ii2WZ": { "defaultMessage": "Révisez votre candidature et envoyez-la!", "description": "Subtitle for the application review page." @@ -1360,7 +1384,7 @@ "description": "Filename for skills CSV file download" }, "4ujx9e": { - "defaultMessage": "Utilisez le bouton « Créer un groupe de compétences » pour commencer.", + "defaultMessage": "Utilisez le bouton « Créez un groupe de compétences » pour commencer.", "description": "Instructions for adding a skill family item." }, "4v9y7U": { @@ -2315,6 +2339,10 @@ "defaultMessage": "Oh! on dirait que vous avez été trop vite!", "description": "Application step skipped page title" }, + "9vluO2": { + "defaultMessage": "Ajouter un membre", + "description": "Header for the add member to team form" + }, "A+4huJ": { "defaultMessage": "Mettre à jour ou supprimer une expérience dans votre chronologie de carrière", "description": "Display text for edit experience form in breadcrumbs" @@ -2583,10 +2611,6 @@ "defaultMessage": "Compte et confidentialité", "description": "Link to the 'Account and privacy' page" }, - "BRd2Xw": { - "defaultMessage": "Créez une collectivité", - "description": "Text to create a community" - }, "BSSYnh": { "defaultMessage": "Nous voulons vous informer qu’entre-temps, des mises à jour sont apportées à ce site qui permettront aux personnes autochtones qui souhaitent se joindre au Programme d’apprentissage en TI de présenter une demande en ligne.", "description": "Second paragraph for apply now dialog" @@ -2615,6 +2639,10 @@ "defaultMessage": "Demande de recherche {searchRequestId} introuvable.", "description": "Message displayed for search request not found on single search request page." }, + "BdpXAF": { + "defaultMessage": "Catégorie d'emploi", + "description": "Label for the employment category radio group" + }, "BdsZwe": { "defaultMessage": "Candidature soumise", "description": "Label for showing the submitted date of an application." @@ -2876,7 +2904,7 @@ "description": "Description of how many items are being displayed out of the total value" }, "Cu+CH3": { - "defaultMessage": "Utilisez le bouton « Créer une collectivité » pour commencer.", + "defaultMessage": "Utilisez le bouton « Créez une collectivité » pour commencer.", "description": "Instructions for adding a community item" }, "CuHYqt": { @@ -3088,7 +3116,7 @@ "description": "Assessment summary" }, "DrR/rp": { - "defaultMessage": "Utilisez le bouton « Ajouter un membre » pour commencer.", + "defaultMessage": "Utilisez le bouton « Ajoutez un membre » pour commencer.", "description": "Instructions for adding a member to a community." }, "Ds7ONS": { @@ -3339,6 +3367,10 @@ "defaultMessage": "Publié", "description": "Title displayed on the Pool table published at column" }, + "FBx3Q4": { + "defaultMessage": "Ajoutez un membre", + "description": "Label for the add member to team form" + }, "FDGVHB": { "defaultMessage": "L’information des ministères ne s’avère pas nécessaire; réduction des exigences en matière de collecte pour les ministères", "description": "third 2024 key change rationale to the directive" @@ -3567,6 +3599,10 @@ "defaultMessage": "Niveau", "description": "Label displayed on classification level input" }, + "GMbOaT": { + "defaultMessage": "Utilisez le bouton « Ajoutez une compétence » pour commencer.", + "description": "Null message description for asset skills table." + }, "GMglI5": { "defaultMessage": "Adresse courriel validée", "description": "The email address has been verified to be owned by user" @@ -3735,6 +3771,10 @@ "defaultMessage": "1 million de dollars à 2,5 millions de dollars", "description": "Contract value range between one-million and two-point-five-million" }, + "HP5PEg": { + "defaultMessage": "Taille de l'organisation", + "description": "Label for the size of the organization radio group" + }, "HRmtdK": { "defaultMessage": "Bien que les Procédures obligatoires soient également efficaces, il est possible d’en améliorer la clarté, de réduire la charge de travail des ministères en matière de rapports et de mieux les aligner sur les nouvelles procédures obligatoires pour les propriétaires fonctionnels lors de l’approvisionnement en services professionnels menées par le Bureau du contrôleur général du Canada (BCG).", "description": "third paragraph describing the 2024 changes to the directive on digital talent" @@ -3859,6 +3899,10 @@ "defaultMessage": "{title} à {organization}", "description": "Title at organization, HTML" }, + "IHyNL8": { + "defaultMessage": "Ajouter un membre", + "description": "Title for the add member to community form" + }, "II4+N3": { "defaultMessage": "Au moyen de la liste des compétences du processus de recrutement, sélectionnez les compétences que vous prévoyez évaluer au moyen de cette méthode d’évaluation.", "description": "description of 'skill selection' section of the 'assessment details' dialog" @@ -4071,6 +4115,10 @@ "defaultMessage": "Employé(e)s (de même niveau)", "description": "Combined eligibility string for 'employees only' and 'at-level only'" }, + "JCZlxS": { + "defaultMessage": "Utilisez le bouton « Ajoutez un rôle dans le processus » pour commencer.", + "description": "Instructions for adding process membership to a user." + }, "JDQvla": { "defaultMessage": "Ces notes sont disponibles pour tous les gestionnaires de ce bassin, mais pas pour les candidats.", "description": "Description of pool candidate notes field" @@ -4275,14 +4323,14 @@ "defaultMessage": "Date d’expiration (heure locale)", "description": "A date at which data will expire, in the local time zone" }, + "KHmf+e": { + "defaultMessage": "Utilisez le bouton « Créez une classification » pour commencer.", + "description": "Instructions for adding a classification item." + }, "KJDxM1": { "defaultMessage": "État du processus", "description": "Title for card for actions related to changing the status of a process" }, - "KKLx+Z": { - "defaultMessage": "Tâches, responsabilités ou autre information clés qui, selon vous, sont essentielles à l’importance de cette expérience.", - "description": "Help text for the experience additional details field" - }, "KKXJFE": { "defaultMessage": "Fiabilité", "description": "Reliability screening level" @@ -4747,6 +4795,10 @@ "defaultMessage": "Modifier votre parcours professionnel", "description": "Edit link text for career timeline section of the application review page." }, + "Mea0Vt": { + "defaultMessage": "Entreprise ou organisme", + "description": "Label for the contracting firm or agency text field" + }, "MejjjQ": { "defaultMessage": "Voici un tableau des équipes, de même que de leurs détails pertinents. Vous pouvez également créer une équipe ou en modifier une qui existe déjà.", "description": "Descriptive text about the list of teams in the admin portal." @@ -4763,6 +4815,10 @@ "defaultMessage": "Processus", "description": "Title for the index pool page" }, + "MkUz+j": { + "defaultMessage": "Ajoutez un membre", + "description": "Label for the add member to community form (action)" + }, "MmTWYV": { "defaultMessage": "Exigences linguistiques pour les personnes candidates", "description": "Link to second language evaluations PSC info page on language requirements dialog" @@ -5063,6 +5119,10 @@ "defaultMessage": "Titre du poste", "description": "Label for an opportunity's job title." }, + "OKqOVT": { + "defaultMessage": "Gouvernement du Canada", + "description": "Label for goc employment category on work experience card metadata" + }, "OM75j3": { "defaultMessage": "La démonstration des compétences permet à un candidat de fournir une série conserve de listes qui mettent en évidence leurs forces, lacunes particulières, de même que leurs occasions de croissances. Ces listes peuvent vous donner un aperçu de l’ensemble plus vaste de compétences d’un candidat, et préciser où ils pourraient être intéressés à apprendre de nouvelles compétences. ", "description": "Lead in text for a users skill showcase for admins." @@ -5331,6 +5391,10 @@ "defaultMessage": "Grade en économie, en sociologie ou en statistique", "description": "Heading for the `just education` option for EC education requirements" }, + "PdkgWB": { + "defaultMessage": "Créez une possibilité de formation", + "description": "Title for link to page to create a training opportunity (imperative in French)" + }, "Pe1kas": { "defaultMessage": "Notes sur les demandes", "description": "Label displayed on the search request form request notes field." @@ -5371,6 +5435,10 @@ "defaultMessage": "Vous avez été supprimé des résultats de la recherche.", "description": "Alert displayed to the user when application card dialog submits successfully." }, + "PrTwov": { + "defaultMessage": "Créez une collectivité", + "description": "Text to create a community (action)" + }, "Ps929U": { "defaultMessage": "Erreur : La mise à jour de votre autodéclaration a échoué", "description": "Message displayed to user after self-declaration fails to be updated." @@ -5735,6 +5803,10 @@ "defaultMessage": "{label} navigation de page", "description": "Label for the table pagination" }, + "RSUgO3": { + "defaultMessage": "Ajoutez une compétence", + "description": "Button text to open the skill dialog and add a skill" + }, "RSkJQR": { "defaultMessage": "Brève description de l'équipe (en français)", "description": "Label for team description in French language" @@ -5827,10 +5899,6 @@ "defaultMessage": "Il manque des données requises par le gouvernement", "description": "Error message displayed when a users government information is incomplete" }, - "RtX9oA": { - "defaultMessage": "Créez une possibilité de formation", - "description": "Title for link to page to create a training opportunity (imperative in French)" - }, "RvB1GT": { "defaultMessage": "Relations de travail", "description": "Label for _labour relations_ option in _authorities involved_ fieldset in the _digital services contracting questionnaire_" @@ -5971,10 +6039,6 @@ "defaultMessage": "Le gouvernement du Canada s’est engagé à financer le perfectionnement de ses spécialistes des TI. Grâce au Fonds de formation et de perfectionnement de la collectivité de la TI, les membres du personnel du groupe TI, représentés par l’Institut professionnel de la fonction publique du Canada (IPFPC), ont désormais accès à une plus vaste gamme de possibilités d’apprentissage afin d’acquérir des compétences et les approfondir.", "description": "First paragraph describing investing in future talent" }, - "SfbDLA": { - "defaultMessage": "Utilisez le bouton « Ajouter un nouveau membre » pour commencer.", - "description": "Instructions for adding a member to a team." - }, "SfhT1q": { "defaultMessage": "Acquérir de l'expérience en matière d'embauche", "description": "Title to get hiring experience" @@ -6171,10 +6235,6 @@ "defaultMessage": "Solutions logicielles de la TI", "description": "Title for the 'software solutions' IT work stream" }, - "Tl2FNA": { - "defaultMessage": "Utilisez le bouton « Créez une classification » pour commencer.", - "description": "Instructions for adding a classification item." - }, "TomxAe": { "defaultMessage": "{time} le {date}", "description": "A datetime formatted as a certain time on a certain date" @@ -6407,7 +6467,7 @@ "description": "Submit button within the search filter dialog" }, "V4W5oL": { - "defaultMessage": "Possibilités de formation dirigée par un instructeur ou une instructrice", + "defaultMessage": "Possibilités de formation dirigées par un instructeur ou une instructrice", "description": "Title for the instructor led training page" }, "V6Y2Np": { @@ -6506,6 +6566,10 @@ "defaultMessage": "Nous aimerions maintenant savoir si vous êtes actuellement employé(e) du gouvernement du Canada. Nous recueillons cette information parce qu'elle nous aide à comprendre, de manière globale, comment les compétences numériques sont réparties entre les différents ministères.", "description": "Message after main heading in employee information page - paragraph 1." }, + "VaToft": { + "defaultMessage": "Utilisez le bouton « Ajoutez une compétence » pour commencer.", + "description": "Null message description for essential skills table." + }, "VaVo2t": { "defaultMessage": "Erreur : Échec de la création du ministère", "description": "Message displayed to user after department fails to get created." @@ -6710,10 +6774,6 @@ "defaultMessage": "Droit de priorité", "description": "Label for applicant's priority entitlement status" }, - "Wd9+xg": { - "defaultMessage": "Utilisez le bouton « Ajouter une nouvelle compétence » pour commencer.", - "description": "Null message description for asset skills table." - }, "WdBt7s": { "defaultMessage": "Approvisionnement", "description": "Label for _procurement_ option in _authorities involved_ fieldset in the _digital services contracting questionnaire_" @@ -7042,6 +7102,10 @@ "defaultMessage": "Communication générale", "description": "Label for preferred language in profile details box." }, + "Y7Qop6": { + "defaultMessage": "Niveau", + "description": "Label displayed on Work Experience form for classification level input" + }, "Y96JXz": { "defaultMessage": "La compétence que vous avez choisie sera aussi ajoutée à votre présentation de compétences, si elle ne s’y trouve pas déjà.", "description": "Subtitle for the find a skill dialog within an experience" @@ -7206,6 +7270,10 @@ "defaultMessage": "Télécopieur : 613-996-9661", "description": "Fax contact info" }, + "Ym2fFN": { + "defaultMessage": "Type d'entrepreneur ou d'entrepreneuse", + "description": "Label for the role seniority radio group" + }, "YmWKlv": { "defaultMessage": "Classification", "description": "Label for a process' classification" @@ -7338,10 +7406,6 @@ "defaultMessage": "Erreur lors du chargement des candidats", "description": "Error message when pool candidates could not be loaded" }, - "ZYqWBR": { - "defaultMessage": "Ajouter une nouvelle compétence", - "description": "Button text to open the skill dialog and add a skill" - }, "ZZpC8s": { "defaultMessage": "Voir les définitions pour « {skillName} »", "description": "Accordion title for skill header on screening decision dialog." @@ -8002,6 +8066,10 @@ "defaultMessage": "4. Hourra! Vous avez terminé de configurer votre compte CléGC et serez ramené à la plateforme Talents numériques du GC.", "description": "Text for fourth sign up -> mfa step." }, + "d1FYv4": { + "defaultMessage": "Classification", + "description": "Label displayed on Work Experience card for classification" + }, "d3HIMV": { "defaultMessage": "Renseignez-vous sur CléGC et trouvez des liens vers des renseignements sur les comptes.", "description": "Introductory text displayed in login and authentication accordion." @@ -8034,6 +8102,10 @@ "defaultMessage": "l’optimisation des résultats de la recherche en matière de l'expérience utilisateur", "description": "List item four, things designers consider for accessibility" }, + "dBpcNA": { + "defaultMessage": "Forces armées canadiennes", + "description": "Label for caf employment category on work experience card metadata" + }, "dD3S0i": { "defaultMessage": "Les employés auront-ils accès à la formation et au perfectionnement pour les ensembles de compétences requis dans le contrat?", "description": "Label for _employees have access to knowledge_ fieldset in the _digital services contracting questionnaire_" @@ -8174,6 +8246,10 @@ "defaultMessage": "Statut du placement", "description": "Label for the job placement status field" }, + "dpZ2B9": { + "defaultMessage": "Entrepreneur ou entrepreneuse", + "description": "Label for contractor employment type on work experience card metadata" + }, "drDPf3": { "defaultMessage": "Parcourez les offres dans le domaine des TI pour la communauté autochtone", "description": "Title for Indigenous community job opportunities on Browse IT jobs page" @@ -9090,10 +9166,6 @@ "defaultMessage": "Affinez les résultats de votre tableau à l'aide des filtres suivants.", "description": "Candidate search filter dialog: subtitle" }, - "hryX4G": { - "defaultMessage": "Utilisez le bouton « Ajoutez des rôles dans des processus  » pour commencer.", - "description": "Instructions for adding process membership to a user." - }, "htxH4r": { "defaultMessage": "Retourner à votre tableau de bord", "description": "Link text to navigate to the profile and applications page" @@ -9290,6 +9362,10 @@ "defaultMessage": "Modifiez les informations sur le groupe de compétences", "description": "Link text to edit a skill family" }, + "ifqj46": { + "defaultMessage": "Le Programme d'apprentissage en TI pour les personnes autochtones a pour but d'aider à éliminer les obstacles en matière d'emploi pour les personnes autochtones dans le domaine numérique au sein du gouvernement du Canada. Devenez un partenaire de recrutement dès aujourd'hui et découvrez comment vous pouvez renforcer votre équipe en embauchant des talents autochtones en informatique et aider à bâtir à une fonction publique plus inclusive. Votre participation contribue à l'objectif plus large de promouvoir l'inclusion, l'équité et la réconciliation au Canada.", + "description": "Paragraph for IT Apprenticeship Program for Indigenous Peoples search card" + }, "iiEGjW": { "defaultMessage": "Nous avons bien reçu votre message.", "description": "Support form success title" @@ -9630,6 +9706,10 @@ "defaultMessage": "Vous pouvez utiliser le bouton « Ajouter une compétence » pour mettre une compétence en vedette ici.", "description": "Secondary message to user when no skills have been attached to experience." }, + "kUqaoo": { + "defaultMessage": "Groupe", + "description": "Label displayed on Work Experience form for classification group input" + }, "kVavip": { "defaultMessage": "Ministère de placement", "description": "Title displayed on the Pool Candidates table placed department column" @@ -9646,6 +9726,10 @@ "defaultMessage": "Lieu de travail et terminologie", "description": "Heading for the pool work location dialog" }, + "kdXBAS": { + "defaultMessage": "Force militaire", + "description": "Label for the military force radio group" + }, "kf5Td+": { "defaultMessage": "Assurez-vous de sauvegarder ou de fermer tout formulaire ouvert avant de continuer.", "description": "Message displayed to users when they attempt to quit the profile form with unsaved changes" @@ -9702,6 +9786,10 @@ "defaultMessage": "Français essentiel", "description": "French essential language requirement" }, + "kyM6sV": { + "defaultMessage": "Pensez-vous embaucher une apprentie ou un apprenti en TI autochtone?", + "description": "Title for IT Apprenticeship Program for Indigenous Peoples search card" + }, "kzd/yK": { "defaultMessage": "Dans votre fuseau horaire actuel, ceci veut dire que les demandes seront acceptées jusqu’à :", "description": "Third paragraph for pool deadlines dialog" @@ -9967,7 +10055,7 @@ "description": "Link to a page to view all the requests" }, "mKrj0x": { - "defaultMessage": "Sauvegarder et ajouter un membre", + "defaultMessage": "Sauvegardez et ajoutez un membre", "description": "Label for add member to a community form" }, "mKzQwr": { @@ -10278,6 +10366,10 @@ "defaultMessage": "Se déconnecter", "description": "Message displayed to users to sign out of the application" }, + "nmx1ym": { + "defaultMessage": " Sélectionnez cette option si l'emploi était dans un ministère ou un organisme fédéral ou une société d'État, ou si vous étiez un entrepreneur ou une entrepreneuse travaillant pour l'une de ces organisations.", + "description": "Description for the goc employment category option in work experience" + }, "nn9B4R": { "defaultMessage": "Postulez dès aujourd’hui pour entamer votre parcours de carrière en TI.", "description": "Homepage subtitle for IT Apprenticeship Program for Indigenous Peoples" @@ -10359,7 +10451,7 @@ "description": "Button label to return to the skills table" }, "oDDr9J": { - "defaultMessage": "Créer un groupe de compétences", + "defaultMessage": "Créez un groupe de compétences", "description": "Heading displayed above the Create Skill family form." }, "oES0/4": { @@ -11062,6 +11154,10 @@ "defaultMessage": "Le processus a été archivé avec succès!", "description": "Message affiché à l'utilisateur après l'archivage du bassin" }, + "s57oJd": { + "defaultMessage": "Utilisez le bouton « Ajoutez un membre » pour commencer.", + "description": "Instructions for adding a member to a team." + }, "s5hTYo": { "defaultMessage": "Rôles dans l'équipe", "description": "Label for the input to select role of a team role" @@ -11482,9 +11578,13 @@ "defaultMessage": "Exigences essentielles", "description": "Sub title for the pool core requirements" }, - "uiuMqi": { - "defaultMessage": "Utilisez le bouton « Ajouter une nouvelle compétence » pour commencer.", - "description": "Null message description for essential skills table." + "uZuEHk": { + "defaultMessage": "Sélectionnez cette option si l'emploi était dans l'Armée canadienne, dans l'Aviation royale canadienne ou dans la Marine royale canadienne, dans la Force régulière ou dans la Force de réserve.", + "description": "Description for the caf employment category option in work experience" + }, + "uaEMMO": { + "defaultMessage": "Type d'emploi", + "description": "Label for the employment type radio group" }, "ukcsxj": { "defaultMessage": "Si vous choisissez de vous autodéclarer dans votre profil et que vous postulez un emploi chez Talents numériques du GC, ces renseignements peuvent être utilisés à n’importe quelle étape du processus d’emploi, de la demande initiale à l’évaluation en passant par la nomination. Les gestionnaires d’embauche ou l’équipe de recrutement de Talents numériques du GC pourraient utiliser ces renseignements", @@ -11730,10 +11830,6 @@ "defaultMessage": "Cette demande a été vérifiée, {expiryDate}.", "description": "Message when a claim as been verified" }, - "wBMn5c": { - "defaultMessage": "Ajouter un membre", - "description": "Label for the add member to community form" - }, "wBU9X4": { "defaultMessage": "Français seulement", "description": "Filter by option on instructor training page." @@ -11775,7 +11871,7 @@ "description": "Placeholder displayed on the skill form families field." }, "wP9+aN": { - "defaultMessage": "Créer un processus", + "defaultMessage": "Créez un processus", "description": "Heading displayed above the Create process form." }, "wPpvvm": { @@ -12035,7 +12131,7 @@ "description": "Message for total estimated candidates box next to search form." }, "xzSXz9": { - "defaultMessage": "Type d’emploi", + "defaultMessage": "Type d'emploi", "description": "Employment type label" }, "y+Pq1f": { @@ -12162,6 +12258,10 @@ "defaultMessage": "Commencez à remplir la section sur vos renseignements en tant que fonctionnaire ", "description": "Call to action to begin editing government information" }, + "yZ0kfQ": { + "defaultMessage": "Tâches, responsabilités ou autre information clés qui, selon vous, sont essentielles à l’importance de cette expérience. La concision est de mise ici : vous aurez plus d'espace pour fournir des détails lorsque vous établirez un lien entre des compétences et cette expérience.", + "description": "Help text for the experience additional details field" + }, "yZMQ6j": { "defaultMessage": "Nous voulons en apprendre davantage sur vous et sur votre intérêt ou votre passion dans le domaine de la TI!", "description": "How it works, step 2 content sentence 1" @@ -12322,6 +12422,10 @@ "defaultMessage": "Retirez {userName} de {poolName}.", "description": "Label for the dialog trigger to remove a user from a process/pool" }, + "zVGzWa": { + "defaultMessage": "Visitez la page du gestionnaire du Programme d'apprentissage en TI pour les personnes autochtones", + "description": "Link to visit IT Apprenticeship Program for Indigenous Peoples manager page" + }, "zXkLL2": { "defaultMessage": "Non démontrée (supprimée du processus)", "description": "Option for assessment decision when candidate has unsuccessful assessment and been removed from the process." diff --git a/apps/web/src/lang/whitelist.yml b/apps/web/src/lang/whitelist.yml index 9d7157ae2d4..02ee8758242 100644 --- a/apps/web/src/lang/whitelist.yml +++ b/apps/web/src/lang/whitelist.yml @@ -29,3 +29,4 @@ - IhPS6D # Important - CdJQ7z # Administration - yWen8A # Format - The format of the training opportunity +- d1FYv4 # Classification diff --git a/apps/web/src/messages/experienceMessages.ts b/apps/web/src/messages/experienceMessages.ts index 5a24e982058..469c16e4ebd 100644 --- a/apps/web/src/messages/experienceMessages.ts +++ b/apps/web/src/messages/experienceMessages.ts @@ -76,6 +76,16 @@ const messages = defineMessages({ id: "lhV7kM", description: "Role at organization, HTML", }, + workWith: { + defaultMessage: "{role} with {group}", + id: "1b+6V1", + description: "Role with group", + }, + workWithHtml: { + defaultMessage: "{role} with {group}", + id: "1syFdp", + description: "Role with group, HTML", + }, collapseDetails: { defaultMessage: "Collapse all experience details", id: "pp+b1H", diff --git a/apps/web/src/pages/ApplicantDashboardPage/ApplicantDashboardPage.tsx b/apps/web/src/pages/ApplicantDashboardPage/ApplicantDashboardPage.tsx new file mode 100644 index 00000000000..778e1ac46c0 --- /dev/null +++ b/apps/web/src/pages/ApplicantDashboardPage/ApplicantDashboardPage.tsx @@ -0,0 +1,77 @@ +/* eslint-disable import/no-unused-modules */ +import { useIntl } from "react-intl"; +import { useQuery } from "urql"; + +import { Pending } from "@gc-digital-talent/ui"; +import { ROLE_NAME } from "@gc-digital-talent/auth"; +import { User, graphql } from "@gc-digital-talent/graphql"; +import { commonMessages } from "@gc-digital-talent/i18n"; + +import SEO from "~/components/SEO/SEO"; +import { getFullNameHtml } from "~/utils/nameUtils"; +import RequireAuth from "~/components/RequireAuth/RequireAuth"; +import Hero from "~/components/Hero"; + +export interface DashboardPageProps { + currentUser?: User | null; +} + +export const DashboardPage = ({ currentUser }: DashboardPageProps) => { + const intl = useIntl(); + + return ( + <> + + + + ); +}; + +const ApplicantDashboard_Query = graphql(/* GraphQL */ ` + query ApplicantDashboard_Query { + me { + id + firstName + lastName + } + } +`); + +export const ApplicantDashboardPageApi = () => { + const [{ data, fetching, error }] = useQuery({ + query: ApplicantDashboard_Query, + }); + + return ( + + + + ); +}; + +export const Component = () => ( + + + +); + +Component.displayName = "ApplicantDashboardPage"; diff --git a/apps/web/src/pages/Applications/ApplicationEducationPage/LinkCareerTimeline.tsx b/apps/web/src/pages/Applications/ApplicationEducationPage/LinkCareerTimeline.tsx index 8fa30681775..e50ea205e57 100644 --- a/apps/web/src/pages/Applications/ApplicationEducationPage/LinkCareerTimeline.tsx +++ b/apps/web/src/pages/Applications/ApplicationEducationPage/LinkCareerTimeline.tsx @@ -13,6 +13,7 @@ import { } from "@gc-digital-talent/graphql"; import { + getExperienceName, isAwardExperience, isCommunityExperience, isEducationExperience, @@ -255,15 +256,7 @@ const LinkCareerTimeline = ({ if (isWorkExperience(experience)) { const workExperience = { value: experience.id, - label: - intl.formatMessage( - { - defaultMessage: "{role} at {organization}", - id: "wTAdQe", - description: "Role at organization", - }, - { role: experience.role, organization: experience.organization }, - ) || "", + label: getExperienceName(experience, intl), }; return { diff --git a/apps/web/src/pages/Applications/ApplicationWelcomePage/ApplicationWelcomePage.tsx b/apps/web/src/pages/Applications/ApplicationWelcomePage/ApplicationWelcomePage.tsx index a6ef9978ea9..314ca0de7e9 100644 --- a/apps/web/src/pages/Applications/ApplicationWelcomePage/ApplicationWelcomePage.tsx +++ b/apps/web/src/pages/Applications/ApplicationWelcomePage/ApplicationWelcomePage.tsx @@ -71,7 +71,7 @@ const ApplicationWelcome = ({ application }: ApplicationPageProps) => { stepOrdinal: currentStepOrdinal, }); const poolName = getShortPoolTitleHtml(intl, { - stream: application.pool.stream, + workStream: application.pool.workStream, name: application.pool.name, publishingGroup: application.pool.publishingGroup, classification: application.pool.classification, diff --git a/apps/web/src/pages/Applications/fragment.ts b/apps/web/src/pages/Applications/fragment.ts index 94a289ed9e9..cde4eea2e35 100644 --- a/apps/web/src/pages/Applications/fragment.ts +++ b/apps/web/src/pages/Applications/fragment.ts @@ -249,8 +249,94 @@ const Application_PoolCandidateFragment = graphql(/* GraphQL */ ` division startDate endDate + employmentCategory { + value + label { + en + fr + } + } + extSizeOfOrganization { + value + label { + en + fr + } + } + extRoleSeniority { + value + label { + en + fr + } + } + govEmploymentType { + value + label { + en + fr + } + } + govPositionType { + value + label { + en + fr + } + } + govContractorRoleSeniority { + value + label { + en + fr + } + } + govContractorType { + value + label { + en + fr + } + } + contractorFirmAgencyName + cafEmploymentType { + value + label { + en + fr + } + } + cafForce { + value + label { + en + fr + } + } + cafRank { + value + label { + en + fr + } + } + classification { + id + group + level + } + department { + id + departmentNumber + name { + en + fr + } + } } } + workEmail + isWorkEmailVerified } pool { id @@ -258,9 +344,9 @@ const Application_PoolCandidateFragment = graphql(/* GraphQL */ ` en fr } - stream { - value - label { + workStream { + id + name { en fr } @@ -408,6 +494,90 @@ const Application_PoolCandidateFragment = graphql(/* GraphQL */ ` startDate endDate details + employmentCategory { + value + label { + en + fr + } + } + extSizeOfOrganization { + value + label { + en + fr + } + } + extRoleSeniority { + value + label { + en + fr + } + } + govEmploymentType { + value + label { + en + fr + } + } + govPositionType { + value + label { + en + fr + } + } + govContractorRoleSeniority { + value + label { + en + fr + } + } + govContractorType { + value + label { + en + fr + } + } + contractorFirmAgencyName + cafEmploymentType { + value + label { + en + fr + } + } + cafForce { + value + label { + en + fr + } + } + cafRank { + value + label { + en + fr + } + } + classification { + id + group + level + } + department { + id + departmentNumber + name { + en + fr + } + } } } submittedSteps diff --git a/apps/web/src/pages/Classifications/components/ClassificationTable.tsx b/apps/web/src/pages/Classifications/components/ClassificationTable.tsx index 03853d50f05..64e9e630ba2 100644 --- a/apps/web/src/pages/Classifications/components/ClassificationTable.tsx +++ b/apps/web/src/pages/Classifications/components/ClassificationTable.tsx @@ -146,8 +146,8 @@ export const ClassificationTable = ({ nullMessage={{ description: intl.formatMessage({ defaultMessage: - 'Use the "Create Classification" button to get started.', - id: "Tl2FNA", + 'Use the "Create classification" button to get started.', + id: "KHmf+e", description: "Instructions for adding a classification item.", }), }} diff --git a/apps/web/src/pages/Communities/CommunityMembersPage/components/AddCommunityMemberDialog.tsx b/apps/web/src/pages/Communities/CommunityMembersPage/components/AddCommunityMemberDialog.tsx index 49428a56441..a6ba8a5d81c 100644 --- a/apps/web/src/pages/Communities/CommunityMembersPage/components/AddCommunityMemberDialog.tsx +++ b/apps/web/src/pages/Communities/CommunityMembersPage/components/AddCommunityMemberDialog.tsx @@ -120,17 +120,15 @@ AddCommunityMemberDialogProps) => { ), })); - const label = intl.formatMessage({ - defaultMessage: "Add member", - id: "wBMn5c", - description: "Label for the add member to community form", - }); - return ( @@ -148,7 +146,11 @@ AddCommunityMemberDialogProps) => { }, )} > - {label} + {intl.formatMessage({ + defaultMessage: "Add member", + id: "IHyNL8", + description: "Title for the add member to community form", + })} diff --git a/apps/web/src/pages/Communities/IndexCommunityPage/components/CommunityTable/CommunityTable.tsx b/apps/web/src/pages/Communities/IndexCommunityPage/components/CommunityTable/CommunityTable.tsx index d53b45b3a6d..c413989354c 100644 --- a/apps/web/src/pages/Communities/IndexCommunityPage/components/CommunityTable/CommunityTable.tsx +++ b/apps/web/src/pages/Communities/IndexCommunityPage/components/CommunityTable/CommunityTable.tsx @@ -130,9 +130,9 @@ export const CommunityTable = ({ linkProps: { href: paths.communityCreate(), label: intl.formatMessage({ - defaultMessage: "Create a community", - id: "BRd2Xw", - description: "Text to create a community", + defaultMessage: "Create community", + id: "PrTwov", + description: "Text to create a community (action)", }), from: currentUrl, }, diff --git a/apps/web/src/pages/Home/IAPManagerHomePage/IAPManagerHomePage.tsx b/apps/web/src/pages/Home/IAPManagerHomePage/IAPManagerHomePage.tsx index dbb9c03a28c..676e34b916b 100644 --- a/apps/web/src/pages/Home/IAPManagerHomePage/IAPManagerHomePage.tsx +++ b/apps/web/src/pages/Home/IAPManagerHomePage/IAPManagerHomePage.tsx @@ -6,6 +6,7 @@ import { ReactNode } from "react"; import { getLocale } from "@gc-digital-talent/i18n"; import { Heading, Link, Well, headingStyles } from "@gc-digital-talent/ui"; +import { buildMailToUri } from "@gc-digital-talent/helpers"; import logoImg from "~/assets/img/iap-logo.svg"; import heroImg from "~/assets/img/IAPManager-Hero.webp"; @@ -26,20 +27,6 @@ const makeLink = (chunks: ReactNode, url: string) => ( ); -function buildMailToUri( - emailAddress: string, - subject: string, - body?: string | null, -) { - const encodedSubject = encodeURIComponent(subject); - let linkBuilder = `mailto:${emailAddress}?subject=${encodedSubject}`; - if (body) { - const encodedBody = encodeURIComponent(body); - linkBuilder += `&body=${encodedBody}`; - } - return linkBuilder; -} - // eslint-disable-next-line import/prefer-default-export export const Component = () => { const intl = useIntl(); diff --git a/apps/web/src/pages/JobPosterTemplates/JobPosterTemplatePage/components/BasicDetails.tsx b/apps/web/src/pages/JobPosterTemplates/JobPosterTemplatePage/components/BasicDetails.tsx index cecd5a82c7b..11f0789aacf 100644 --- a/apps/web/src/pages/JobPosterTemplates/JobPosterTemplatePage/components/BasicDetails.tsx +++ b/apps/web/src/pages/JobPosterTemplates/JobPosterTemplatePage/components/BasicDetails.tsx @@ -29,8 +29,8 @@ const JobPosterTemplateBasicDetails_Fragment = graphql(/* GraphQL */ ` group level } - stream { - label { + workStream { + name { en fr } @@ -121,7 +121,7 @@ const BasicDetails = ({ jobPosterTemplateQuery }: BasicDetailsProps) => { "Label displayed on the pool form stream/job title field.", })} > - {getLocalizedName(jobPosterTemplate.stream?.label, intl)} + {getLocalizedName(jobPosterTemplate.workStream?.name, intl)} ): boolean { function previewMetaData( intl: IntlShape, classification?: Maybe, - stream?: Maybe, + workStream?: Maybe, ): PreviewMetaData[] { const metaData = []; if (classification) { @@ -137,11 +136,11 @@ function previewMetaData( } satisfies PreviewMetaData); } - if (stream) { + if (workStream) { metaData.push({ - key: stream.value, + key: workStream.id, type: "text", - children: getLocalizedName(stream.label, intl), + children: getLocalizedName(workStream.name, intl), } satisfies PreviewMetaData); } @@ -225,7 +224,7 @@ const JobPosterTemplatesPage = () => { ); show = show && - assertIncludes(formData.streams, jobPosterTemplate?.stream?.value); + assertIncludes(formData.workStreams, jobPosterTemplate?.workStream?.id); return show; }); @@ -256,7 +255,7 @@ const JobPosterTemplatesPage = () => { formData.keyword, formData.classifications, formData.supervisoryStatuses, - formData.streams, + formData.workStreams, locale, sortBy, intl, @@ -374,13 +373,13 @@ const JobPosterTemplatesPage = () => { })} /> ({ + value: workStream.id, + label: getLocalizedName(workStream.name, intl), + })), )} legend={intl.formatMessage({ defaultMessage: "Filter by work streams", @@ -497,7 +496,7 @@ const JobPosterTemplatesPage = () => { metaData={previewMetaData( intl, jobPosterTemplate.classification, - jobPosterTemplate.stream, + jobPosterTemplate.workStream, )} > {jobPosterTemplate.description && ( diff --git a/apps/web/src/pages/Manager/components/ReviewTalentRequestDialog.tsx b/apps/web/src/pages/Manager/components/ReviewTalentRequestDialog.tsx index 1567a325f51..cd592bc0e9f 100644 --- a/apps/web/src/pages/Manager/components/ReviewTalentRequestDialog.tsx +++ b/apps/web/src/pages/Manager/components/ReviewTalentRequestDialog.tsx @@ -55,8 +55,8 @@ const ReviewTalentRequestDialog_Query = graphql(/* GraphQL */ ` group level } - qualifiedStreams { - label { + workStreams { + name { fr en } @@ -126,7 +126,7 @@ const ReviewTalentRequestDialogContent = ({ const classifications = unpackMaybes( request.applicantFilter?.qualifiedClassifications, ); - const workStreams = unpackMaybes(request.applicantFilter?.qualifiedStreams); + const workStreams = unpackMaybes(request.applicantFilter?.workStreams); const equityDescriptions = equitySelectionsToDescriptions( request.applicantFilter?.equity, intl, @@ -189,7 +189,7 @@ const ReviewTalentRequestDialogContent = ({ {workStreams.length > 0 ? deriveSingleString( workStreams, - (stream) => getLocalizedName(stream.label, intl), + (workStream) => getLocalizedName(workStream.name, intl), locale, ) : nullMessage} diff --git a/apps/web/src/pages/PoolCandidates/ViewPoolCandidatePage/ViewPoolCandidatePage.tsx b/apps/web/src/pages/PoolCandidates/ViewPoolCandidatePage/ViewPoolCandidatePage.tsx index c0077a929b7..c07fc1e027a 100644 --- a/apps/web/src/pages/PoolCandidates/ViewPoolCandidatePage/ViewPoolCandidatePage.tsx +++ b/apps/web/src/pages/PoolCandidates/ViewPoolCandidatePage/ViewPoolCandidatePage.tsx @@ -105,9 +105,9 @@ const PoolCandidate_SnapshotQuery = graphql(/* GraphQL */ ` group level } - stream { - value - label { + workStream { + id + name { en fr } @@ -168,7 +168,7 @@ export const ViewPoolCandidate = ({ }, { label: getFullPoolTitleLabel(intl, { - stream: poolCandidate.pool.stream, + workStream: poolCandidate.pool.workStream, name: poolCandidate.pool.name, publishingGroup: poolCandidate.pool.publishingGroup, classification: poolCandidate.pool.classification, diff --git a/apps/web/src/pages/Pools/EditPoolPage/EditPoolPage.tsx b/apps/web/src/pages/Pools/EditPoolPage/EditPoolPage.tsx index 287e60f5e1b..f7a3b8c4d1e 100644 --- a/apps/web/src/pages/Pools/EditPoolPage/EditPoolPage.tsx +++ b/apps/web/src/pages/Pools/EditPoolPage/EditPoolPage.tsx @@ -102,9 +102,9 @@ export const EditPool_Fragment = graphql(/* GraphQL */ ` ...EditPoolYourImpact id - stream { - value - label { + workStream { + id + name { en fr } @@ -277,7 +277,7 @@ export const EditPoolForm = ({ areaOfSelection: pool.areaOfSelection, classification: pool.classification, department: pool.department, - stream: pool.stream, + workStream: pool.workStream, name: pool.name, processNumber: pool.processNumber, publishingGroup: pool.publishingGroup, @@ -315,7 +315,7 @@ export const EditPoolForm = ({ areaOfSelection: pool.areaOfSelection, classification: pool.classification, department: pool.department, - stream: pool.stream, + workStream: pool.workStream, name: pool.name, processNumber: pool.processNumber, publishingGroup: pool.publishingGroup, @@ -370,7 +370,7 @@ export const EditPoolForm = ({ educationRequirements: { id: "education-requirements", hasError: educationRequirementIsNull({ - stream: pool.stream, + workStream: pool.workStream, name: pool.name, processNumber: pool.processNumber, publishingGroup: pool.publishingGroup, diff --git a/apps/web/src/pages/Pools/EditPoolPage/components/AssetSkillsSection.tsx b/apps/web/src/pages/Pools/EditPoolPage/components/AssetSkillsSection.tsx index 20996979008..4af8cbf5f53 100644 --- a/apps/web/src/pages/Pools/EditPoolPage/components/AssetSkillsSection.tsx +++ b/apps/web/src/pages/Pools/EditPoolPage/components/AssetSkillsSection.tsx @@ -131,8 +131,8 @@ const AssetSkillsSection = ({ description: "Null message title for asset skills table.", }), description: intl.formatMessage({ - defaultMessage: `Use the "Add a new skill" button to get started.`, - id: "Wd9+xg", + defaultMessage: `Use the "Add skill" button to get started.`, + id: "GMbOaT", description: "Null message description for asset skills table.", }), }} diff --git a/apps/web/src/pages/Pools/EditPoolPage/components/EssentialSkillsSection.tsx b/apps/web/src/pages/Pools/EditPoolPage/components/EssentialSkillsSection.tsx index df0cfe21859..03c431e9969 100644 --- a/apps/web/src/pages/Pools/EditPoolPage/components/EssentialSkillsSection.tsx +++ b/apps/web/src/pages/Pools/EditPoolPage/components/EssentialSkillsSection.tsx @@ -131,8 +131,8 @@ const EssentialSkillsSection = ({ description: "Null message title for essential skills table.", }), description: intl.formatMessage({ - defaultMessage: `Use the "Add a new skill" button to get started.`, - id: "uiuMqi", + defaultMessage: `Use the "Add skill" button to get started.`, + id: "VaToft", description: "Null message description for essential skills table.", }), }} diff --git a/apps/web/src/pages/Pools/EditPoolPage/components/PoolNameSection/Display.tsx b/apps/web/src/pages/Pools/EditPoolPage/components/PoolNameSection/Display.tsx index a347f6bfa0a..56a463c9bf6 100644 --- a/apps/web/src/pages/Pools/EditPoolPage/components/PoolNameSection/Display.tsx +++ b/apps/web/src/pages/Pools/EditPoolPage/components/PoolNameSection/Display.tsx @@ -29,7 +29,7 @@ const Display = ({ selectionLimitations: poolSelectionLimitations, classification, department, - stream, + workStream, name, processNumber, publishingGroup, @@ -105,10 +105,10 @@ const Display = ({ : notProvided} - {getLocalizedName(stream?.label, intl)} + {getLocalizedName(workStream?.name, intl)} ({ + value: workStream.id, + label: getLocalizedName(workStream?.name, intl), + }), + )} disabled={formDisabled} /> ; classification?: Classification["id"]; department?: Department["id"]; - stream?: PoolStream; + stream?: WorkStream["id"]; specificTitleEn?: LocalizedString["en"]; specificTitleFr?: LocalizedString["fr"]; processNumber?: string; @@ -35,7 +35,7 @@ export const dataToFormValues = (initialData: Pool): FormValues => ({ selectionLimitations: initialData.selectionLimitations?.map((l) => l.value), classification: initialData.classification?.id ?? "", department: initialData.department?.id ?? "", - stream: initialData.stream?.value ?? undefined, + stream: initialData.workStream?.id ?? undefined, specificTitleEn: initialData.name?.en ?? "", specificTitleFr: initialData.name?.fr ?? "", processNumber: initialData.processNumber ?? "", @@ -50,7 +50,7 @@ export type PoolNameSubmitData = Pick< | "classification" | "department" | "name" - | "stream" + | "workStream" | "processNumber" | "publishingGroup" | "opportunityLength" @@ -71,7 +71,7 @@ export const formValuesToSubmitData = ( connect: formValues.department, } : undefined, - stream: formValues.stream ? formValues.stream : undefined, + workStream: formValues.stream ? { connect: formValues.stream } : undefined, name: { en: formValues.specificTitleEn, fr: formValues.specificTitleFr, diff --git a/apps/web/src/pages/Pools/EditPoolPage/components/UpdatePublishedProcessDialog/UpdatePublishedProcessDialog.tsx b/apps/web/src/pages/Pools/EditPoolPage/components/UpdatePublishedProcessDialog/UpdatePublishedProcessDialog.tsx index c0b3b0199cf..ca62d256eb9 100644 --- a/apps/web/src/pages/Pools/EditPoolPage/components/UpdatePublishedProcessDialog/UpdatePublishedProcessDialog.tsx +++ b/apps/web/src/pages/Pools/EditPoolPage/components/UpdatePublishedProcessDialog/UpdatePublishedProcessDialog.tsx @@ -23,9 +23,9 @@ import { PublishedEditableSectionProps } from "../../types"; const UpdatePublishedProcessDialog_Fragment = graphql(/* GraphQL */ ` fragment UpdatePublishedProcessDialog on Pool { id - stream { - value - label { + workStream { + id + name { en fr } @@ -64,7 +64,7 @@ const UpdatePublishedProcessDialog = ({ const [isOpen, setIsOpen] = useState(false); const pool = getFragment(UpdatePublishedProcessDialog_Fragment, poolQuery); const title = getShortPoolTitleHtml(intl, { - stream: pool.stream, + workStream: pool.workStream, name: pool.name, publishingGroup: pool.publishingGroup, classification: pool.classification, diff --git a/apps/web/src/pages/Pools/IndexPoolPage/components/PoolFilterDialog.tsx b/apps/web/src/pages/Pools/IndexPoolPage/components/PoolFilterDialog.tsx index 3dba45dda12..0b5136fd9dc 100644 --- a/apps/web/src/pages/Pools/IndexPoolPage/components/PoolFilterDialog.tsx +++ b/apps/web/src/pages/Pools/IndexPoolPage/components/PoolFilterDialog.tsx @@ -4,14 +4,13 @@ import { Combobox, localizedEnumToOptions } from "@gc-digital-talent/forms"; import { FragmentType, PoolStatus, - PoolStream, PublishingGroup, Scalars, getFragment, graphql, } from "@gc-digital-talent/graphql"; import { unpackMaybes } from "@gc-digital-talent/helpers"; -import { commonMessages } from "@gc-digital-talent/i18n"; +import { commonMessages, getLocalizedName } from "@gc-digital-talent/i18n"; import FilterDialog, { CommonFilterDialogProps, @@ -22,7 +21,7 @@ export interface FormValues { publishingGroups: PublishingGroup[]; statuses: PoolStatus[]; classifications: Scalars["UUID"]["output"][]; - streams: PoolStream[]; + workStreams: Scalars["UUID"]["output"][]; } const PoolFilterDialogOptions_Fragment = graphql(/* GraphQL */ ` @@ -45,9 +44,9 @@ const PoolFilterDialogOptions_Fragment = graphql(/* GraphQL */ ` fr } } - streams: localizedEnumStrings(enumName: "PoolStream") { - value - label { + workStreams { + id + name { en fr } @@ -92,11 +91,14 @@ const PoolFilterDialog = ({ options={localizedEnumToOptions(data?.statuses, intl)} /> ({ + value: workStream.id, + label: getLocalizedName(workStream.name, intl), + }))} /> { first: paginationState.pageSize, orderByPoolBookmarks: getPoolBookmarkSort(), orderByTeamDisplayName: getTeamDisplayNameSort(sortState, locale), + orderByWorkStreamName: getWorkStreamNameSort(sortState, locale), orderByColumn: getOrderByColumnSort(sortState), orderBy: sortState ? getOrderByClause(sortState) : undefined, }, @@ -299,7 +303,8 @@ const PoolTable = ({ title, initialFilterInput }: PoolTableProps) => { }, }), columnHelper.accessor( - (row) => poolNameAccessor({ name: row.name, stream: row.stream }, intl), + (row) => + poolNameAccessor({ name: row.name, workStream: row.workStream }, intl), { id: "name", header: intl.formatMessage(commonMessages.name), @@ -323,9 +328,9 @@ const PoolTable = ({ title, initialFilterInput }: PoolTableProps) => { classificationCell(pool.classification), }), columnHelper.accessor( - ({ stream }) => getLocalizedName(stream?.label, intl), + ({ workStream }) => getLocalizedName(workStream?.name, intl), { - id: "stream", + id: "workStream", enableColumnFilter: false, header: intl.formatMessage({ defaultMessage: "Stream", diff --git a/apps/web/src/pages/Pools/IndexPoolPage/components/helpers.tsx b/apps/web/src/pages/Pools/IndexPoolPage/components/helpers.tsx index a5918bf69a5..05a98208d70 100644 --- a/apps/web/src/pages/Pools/IndexPoolPage/components/helpers.tsx +++ b/apps/web/src/pages/Pools/IndexPoolPage/components/helpers.tsx @@ -16,6 +16,7 @@ import { PoolBookmarksOrderByInput, PoolFilterInput, PoolTeamDisplayNameOrderByInput, + PoolWorkStreamNameOrderByInput, QueryPoolsPaginatedOrderByClassificationColumn, QueryPoolsPaginatedOrderByRelationOrderByClause, QueryPoolsPaginatedOrderByUserColumn, @@ -32,11 +33,11 @@ import { FormValues } from "./PoolFilterDialog"; import PoolBookmark, { PoolBookmark_Fragment } from "./PoolBookmark"; export function poolNameAccessor( - pool: Pick, + pool: Pick, intl: IntlShape, ) { const name = getLocalizedName(pool.name, intl); - return `${name.toLowerCase()} ${getLocalizedName(pool.stream?.label, intl, true)}`; + return `${name.toLowerCase()} ${getLocalizedName(pool?.workStream?.name, intl, true)}`; } export function viewCell( @@ -173,7 +174,6 @@ export function getOrderByClause( ["id", "id"], ["name", "name"], ["publishingGroup", "publishing_group"], - ["stream", "stream"], ["processNumber", "process_number"], ["ownerName", "FIRST_NAME"], ["ownerEmail", "EMAIL"], @@ -260,6 +260,20 @@ export function getTeamDisplayNameSort( }; } +export function getWorkStreamNameSort( + sortingRules?: SortingState, + locale?: Locales, +): PoolWorkStreamNameOrderByInput | undefined { + const sortingRule = sortingRules?.find((rule) => rule.id === "workStream"); + + if (!sortingRule) return undefined; + + return { + locale: locale ?? "en", + order: sortingRule.desc ? SortOrder.Desc : SortOrder.Asc, + }; +} + export function getOrderByColumnSort( sortingRules?: SortingState, ): OrderByColumnInput | undefined { @@ -296,7 +310,7 @@ export function transformFormValuesToFilterInput( return { publishingGroups: data.publishingGroups, statuses: data.statuses, - streams: data.streams, + workStreams: data.workStreams, classifications: data.classifications.map((classification) => { const [group, level] = classification.split("-"); return { group, level: Number(level) }; @@ -310,7 +324,7 @@ export function transformPoolFilterInputToFormValues( return { publishingGroups: unpackMaybes(input?.publishingGroups), statuses: unpackMaybes(input?.statuses), - streams: unpackMaybes(input?.streams), + workStreams: unpackMaybes(input?.workStreams), classifications: unpackMaybes(input?.classifications).map( (c) => `${c.group}-${c.level}`, ), diff --git a/apps/web/src/pages/Pools/ManageAccessPage/components/AddPoolMembershipDialog.tsx b/apps/web/src/pages/Pools/ManageAccessPage/components/AddPoolMembershipDialog.tsx index eec30f69f0b..6f8f3227f7a 100644 --- a/apps/web/src/pages/Pools/ManageAccessPage/components/AddPoolMembershipDialog.tsx +++ b/apps/web/src/pages/Pools/ManageAccessPage/components/AddPoolMembershipDialog.tsx @@ -120,21 +120,25 @@ const AddPoolMembershipDialog = ({ ), })); - const label = intl.formatMessage({ - defaultMessage: "Add member", - id: "wBMn5c", - description: "Label for the add member to community form", - }); - return ( - {label} + + {intl.formatMessage({ + defaultMessage: "Add member", + id: "IHyNL8", + description: "Title for the add member to community form", + })} +
diff --git a/apps/web/src/pages/Pools/PoolAdvertisementPage/PoolAdvertisementPage.tsx b/apps/web/src/pages/Pools/PoolAdvertisementPage/PoolAdvertisementPage.tsx index b38941eed9e..44c50d36f4c 100644 --- a/apps/web/src/pages/Pools/PoolAdvertisementPage/PoolAdvertisementPage.tsx +++ b/apps/web/src/pages/Pools/PoolAdvertisementPage/PoolAdvertisementPage.tsx @@ -136,9 +136,9 @@ export const PoolAdvertisement_Fragment = graphql(/* GraphQL */ ` en fr } - stream { - value - label { + workStream { + id + name { en fr } @@ -253,9 +253,9 @@ export const PoolAdvertisement_Fragment = graphql(/* GraphQL */ ` en fr } - stream { - value - label { + workStream { + id + name { en fr } @@ -328,13 +328,13 @@ export const PoolPoster = ({ }); } const poolTitle = getShortPoolTitleLabel(intl, { - stream: pool.stream, + workStream: pool.workStream, name: pool.name, publishingGroup: pool.publishingGroup, classification: pool.classification, }); const fullPoolTitle = getFullPoolTitleHtml(intl, { - stream: pool.stream, + workStream: pool.workStream, name: pool.name, publishingGroup: pool.publishingGroup, classification: pool.classification, @@ -664,7 +664,7 @@ export const PoolPoster = ({ description: "Label for pool advertisement stream", }) + intl.formatMessage(commonMessages.dividingColon) } - value={getLocalizedName(pool.stream?.label, intl)} + value={getLocalizedName(pool?.workStream?.name, intl)} suffix={ classification?.group === "IT" ? ( { return currentPage?.title; } return getShortPoolTitleLabel(intl, { - stream: pool.stream, + workStream: pool.workStream, name: pool.name, publishingGroup: pool.publishingGroup, classification: pool.classification, @@ -127,7 +127,7 @@ const PoolHeader = ({ poolQuery }: PoolHeaderProps) => { id: pool.id, name: pool.name, publishingGroup: pool.publishingGroup, - stream: pool.stream, + workStream: pool.workStream, classification: pool.classification, }); const currentPage = useCurrentPage(pages); diff --git a/apps/web/src/pages/Pools/ViewPoolPage/ViewPoolPage.tsx b/apps/web/src/pages/Pools/ViewPoolPage/ViewPoolPage.tsx index f3faa8e5b34..343855d3d38 100644 --- a/apps/web/src/pages/Pools/ViewPoolPage/ViewPoolPage.tsx +++ b/apps/web/src/pages/Pools/ViewPoolPage/ViewPoolPage.tsx @@ -71,9 +71,9 @@ export const ViewPool_Fragment = graphql(/* GraphQL */ ` } closingDate processNumber - stream { - value - label { + workStream { + id + name { en fr } @@ -123,7 +123,7 @@ export const ViewPool = ({ const { roleAssignments } = useAuthorization(); const pool = getFragment(ViewPool_Fragment, poolQuery); const poolName = getShortPoolTitleHtml(intl, { - stream: pool.stream, + workStream: pool.workStream, name: pool.name, publishingGroup: pool.publishingGroup, classification: pool.classification, diff --git a/apps/web/src/pages/Profile/AccountSettings/AccountSettingsPage.tsx b/apps/web/src/pages/Profile/AccountSettings/AccountSettingsPage.tsx index 750998227d1..cbc93dd6149 100644 --- a/apps/web/src/pages/Profile/AccountSettings/AccountSettingsPage.tsx +++ b/apps/web/src/pages/Profile/AccountSettings/AccountSettingsPage.tsx @@ -12,12 +12,14 @@ import { } from "@gc-digital-talent/ui"; import { graphql } from "@gc-digital-talent/graphql"; import { unpackMaybes } from "@gc-digital-talent/helpers"; +import { ROLE_NAME } from "@gc-digital-talent/auth"; import useBreadcrumbs from "~/hooks/useBreadcrumbs"; import useRoutes from "~/hooks/useRoutes"; import SEO from "~/components/SEO/SEO"; import Hero from "~/components/Hero"; import profileMessages from "~/messages/profileMessages"; +import RequireAuth from "~/components/RequireAuth/RequireAuth"; import AccountManagement from "./AccountManagement"; import RecruitmentAvailability from "./RecruitmentAvailability"; @@ -65,7 +67,7 @@ const inlineLink = (href: string, chunks: ReactNode) => ( ); -export const Component = () => { +const AccountSettingsPage = () => { const intl = useIntl(); const paths = useRoutes(); @@ -238,12 +240,12 @@ export const Component = () => { ); }; -// export const Component = () => ( -// -// -// -// ); +export const Component = () => ( + + + +); Component.displayName = "AccountSettingsPage"; -export default Component; +export default AccountSettingsPage; diff --git a/apps/web/src/pages/Profile/CareerTimelineAndRecruitmentPage/components/CareerTimelineAndRecruitment.tsx b/apps/web/src/pages/Profile/CareerTimelineAndRecruitmentPage/components/CareerTimelineAndRecruitment.tsx index 95c8db4cd0a..5550e064081 100644 --- a/apps/web/src/pages/Profile/CareerTimelineAndRecruitmentPage/components/CareerTimelineAndRecruitment.tsx +++ b/apps/web/src/pages/Profile/CareerTimelineAndRecruitmentPage/components/CareerTimelineAndRecruitment.tsx @@ -120,6 +120,90 @@ export const CareerTimelineExperience_Fragment = graphql(/* GraphQL */ ` division startDate endDate + employmentCategory { + value + label { + en + fr + } + } + extSizeOfOrganization { + value + label { + en + fr + } + } + extRoleSeniority { + value + label { + en + fr + } + } + govEmploymentType { + value + label { + en + fr + } + } + govPositionType { + value + label { + en + fr + } + } + govContractorRoleSeniority { + value + label { + en + fr + } + } + govContractorType { + value + label { + en + fr + } + } + contractorFirmAgencyName + cafEmploymentType { + value + label { + en + fr + } + } + cafForce { + value + label { + en + fr + } + } + cafRank { + value + label { + en + fr + } + } + classification { + id + group + level + } + department { + id + departmentNumber + name { + en + fr + } + } } } `); @@ -144,9 +228,6 @@ const CareerTimelineApplication_Fragment = graphql(/* GraphQL */ ` publishingGroup { value } - stream { - value - } } } `); diff --git a/apps/web/src/pages/Profile/ExperienceFormPage/ExperienceForm.test.tsx b/apps/web/src/pages/Profile/ExperienceFormPage/ExperienceForm.test.tsx deleted file mode 100644 index 2267978a61a..00000000000 --- a/apps/web/src/pages/Profile/ExperienceFormPage/ExperienceForm.test.tsx +++ /dev/null @@ -1,393 +0,0 @@ -/** - * @jest-environment jsdom - */ -import "@testing-library/jest-dom"; -import { Provider as GraphqlProvider } from "urql"; -import { act, screen, waitFor } from "@testing-library/react"; -import { userEvent } from "@testing-library/user-event"; -import { never, fromValue } from "wonka"; - -import { fakeSkills } from "@gc-digital-talent/fake-data"; -import { - axeTest, - renderWithProviders, - updateDate, -} from "@gc-digital-talent/jest-helpers"; -import { - AwardedScope, - AwardedTo, - makeFragmentData, -} from "@gc-digital-talent/graphql"; - -import type { ExperienceType } from "~/types/experience"; - -import { - ExperienceForm, - ExperienceFormProps, - ExperienceFormSkill_Fragment, -} from "./ExperienceFormPage"; - -const mockUserId = "user-id"; -const mockSkills = fakeSkills(50); -const mockClient = { - executeMutation: jest.fn(() => never), - executeQuery: jest.fn(() => - fromValue({ - data: { - awardedTo: [{ value: AwardedTo.Me, label: { en: "Me", fr: "Me" } }], - awardedScopes: [ - { value: AwardedScope.Local, label: { en: "Local", fr: "Local" } }, - ], - }, - }), - ), -}; - -const skillFragments = mockSkills.map((skill) => - makeFragmentData(skill, ExperienceFormSkill_Fragment), -); - -const renderExperienceForm = (props: ExperienceFormProps) => - renderWithProviders( - - - , - ); - -describe("ExperienceForm", () => { - const user = userEvent.setup(); - - it("award type should have no accessibility errors", async () => { - const { container } = renderExperienceForm({ - userId: mockUserId, - experienceType: "award", - skillsQuery: skillFragments, - }); - await axeTest(container); - }); - - it("community type should have no accessibility errors", async () => { - const { container } = renderExperienceForm({ - userId: mockUserId, - experienceType: "community", - skillsQuery: skillFragments, - }); - await axeTest(container); - }); - - it("education type should have no accessibility errors", async () => { - const { container } = renderExperienceForm({ - userId: mockUserId, - experienceType: "education", - skillsQuery: skillFragments, - }); - await axeTest(container); - }); - - it("personal type should have no accessibility errors", async () => { - const { container } = renderExperienceForm({ - userId: mockUserId, - experienceType: "personal", - skillsQuery: skillFragments, - }); - await axeTest(container); - }); - - it("work type should have no accessibility errors", async () => { - const { container } = renderExperienceForm({ - userId: mockUserId, - experienceType: "work", - skillsQuery: skillFragments, - }); - await axeTest(container); - }); - - it("should render award fields", () => { - renderExperienceForm({ - userId: mockUserId, - experienceType: "award", - skillsQuery: skillFragments, - }); - - expect( - screen.getByRole("textbox", { name: /award title/i }), - ).toBeInTheDocument(); - - expect( - screen.getByRole("combobox", { name: /awarded to/i }), - ).toBeInTheDocument(); - - expect( - screen.getByRole("textbox", { name: /issuing/i }), - ).toBeInTheDocument(); - - expect( - screen.getByRole("combobox", { name: /award scope/i }), - ).toBeInTheDocument(); - - // Note: Date inputs have no role by default - expect( - screen.getByRole("group", { name: /date awarded/i }), - ).toBeInTheDocument(); - }); - - it("should render community fields", () => { - renderExperienceForm({ - userId: mockUserId, - experienceType: "community", - skillsQuery: skillFragments, - }); - - expect( - screen.getByRole("textbox", { name: /my role/i }), - ).toBeInTheDocument(); - - expect(screen.getByRole("textbox", { name: /group/i })).toBeInTheDocument(); - - expect( - screen.getByRole("textbox", { name: /project/i }), - ).toBeInTheDocument(); - - expect( - screen.getByRole("group", { name: /start date/i }), - ).toBeInTheDocument(); - - expect( - screen.getByRole("group", { name: /end date/i }), - ).toBeInTheDocument(); - }); - - it("should render education fields", () => { - renderExperienceForm({ - userId: mockUserId, - experienceType: "education", - skillsQuery: skillFragments, - }); - - expect( - screen.getByRole("combobox", { name: /type of education/i }), - ).toBeInTheDocument(); - - expect( - screen.getByRole("textbox", { name: /area of study/i }), - ).toBeInTheDocument(); - - expect( - screen.getByRole("textbox", { name: /institution/i }), - ).toBeInTheDocument(); - - expect( - screen.getByRole("combobox", { name: /status/i }), - ).toBeInTheDocument(); - - expect( - screen.getByRole("textbox", { name: /thesis title/i }), - ).toBeInTheDocument(); - - expect( - screen.getByRole("group", { name: /start date/i }), - ).toBeInTheDocument(); - - expect( - screen.getByRole("group", { name: /end date/i }), - ).toBeInTheDocument(); - }); - - it("should render personal fields", () => { - renderExperienceForm({ - userId: mockUserId, - experienceType: "personal", - skillsQuery: skillFragments, - }); - - expect( - screen.getByRole("textbox", { name: /short title/i }), - ).toBeInTheDocument(); - - expect( - screen.getByRole("textbox", { name: /experience description/i }), - ).toBeInTheDocument(); - - expect( - screen.getByRole("group", { name: /disclaimer/i }), - ).toBeInTheDocument(); - - expect( - screen.getByRole("group", { name: /current experience/i }), - ).toBeInTheDocument(); - - expect( - screen.getByRole("group", { name: /start date/i }), - ).toBeInTheDocument(); - - expect( - screen.getByRole("group", { name: /end date/i }), - ).toBeInTheDocument(); - }); - - it("should render work fields", () => { - renderExperienceForm({ - userId: mockUserId, - experienceType: "work", - skillsQuery: skillFragments, - }); - - expect( - screen.getByRole("textbox", { name: /my role/i }), - ).toBeInTheDocument(); - - expect( - screen.getByRole("textbox", { name: /organization/i }), - ).toBeInTheDocument(); - - expect(screen.getByRole("textbox", { name: /team/i })).toBeInTheDocument(); - - expect( - screen.getByRole("group", { name: /current role/i }), - ).toBeInTheDocument(); - - expect( - screen.getByRole("group", { name: /start date/i }), - ).toBeInTheDocument(); - - expect( - screen.getByRole("group", { name: /end date/i }), - ).toBeInTheDocument(); - }); - - it("should render additional details", () => { - renderExperienceForm({ - userId: mockUserId, - experienceType: "work", // Type of form shouldn't matter here - skillsQuery: skillFragments, - }); - - expect( - screen.getByRole("heading", { name: /highlight additional details/i }), - ).toBeInTheDocument(); - }); - - it("should render link featured skills", () => { - renderExperienceForm({ - userId: mockUserId, - experienceType: "work", // Type of form shouldn't matter here - skillsQuery: skillFragments, - }); - - expect( - screen.getByRole("heading", { name: /link featured skills/i }), - ).toBeInTheDocument(); - }); - - it("should not submit award with empty fields", async () => { - renderExperienceForm({ - userId: mockUserId, - experienceType: "award", - skillsQuery: skillFragments, - }); - - expect(await screen.findByText(/save and return/i)).toBeInTheDocument(); - - await user.click(screen.getByRole("button", { name: /save and return/i })); - - expect(mockClient.executeMutation).not.toHaveBeenCalled(); - }); - - it("should submit with required fields", async () => { - const experienceType: ExperienceType = "award"; - renderExperienceForm({ - userId: mockUserId, - experienceType, - skillsQuery: skillFragments, - }); - - expect(await screen.findByText(/save and return/i)).toBeInTheDocument(); - - const awardTitle = screen.getByRole("textbox", { name: /award title/i }); - await user.type(awardTitle, "AwardTitle"); - expect(awardTitle).toHaveValue("AwardTitle"); - - const awardedTo = screen.getByRole("combobox", { name: /awarded to/i }); - await user.selectOptions(awardedTo, "ME"); - expect(awardedTo).toHaveValue("ME"); - - const organization = screen.getByRole("textbox", { - name: /issuing organization/i, - }); - await user.clear(organization); - expect(organization).toHaveValue(""); - await user.type(organization, "Org"); - expect(organization).toHaveValue("Org"); - - const dateAwarded = screen.getByRole("group", { name: /date awarded/i }); - await updateDate(dateAwarded, { - year: "1111", - month: "11", - }); - expect(screen.getByRole("spinbutton", { name: /year/i })).toHaveValue(1111); - expect(screen.getByRole("combobox", { name: /month/i })).toHaveValue("11"); - - const scope = screen.getByRole("combobox", { name: /award scope/i }); - await user.selectOptions(scope, "LOCAL"); - expect(scope).toHaveValue("LOCAL"); - - const details = screen.getByRole("textbox", { - name: /additional details/i, - }); - await user.clear(details); - await user.type(details, "details"); - expect(details).toHaveValue("details"); - - await user.click(screen.getByRole("button", { name: /save and return/i })); - - await waitFor(() => expect(screen.queryAllByRole("alert")).toHaveLength(0)); - }); - - it("should add skill", () => { - renderExperienceForm({ - userId: mockUserId, - experienceType: "award", - skillsQuery: skillFragments, - }); - - act(() => { - screen - .getAllByRole("button", { - name: /add a skill/i, - })[0] - .click(); - }); - }); - - it("delete should not render when edit is false", () => { - renderExperienceForm({ - userId: mockUserId, - experienceType: "award", - skillsQuery: skillFragments, - edit: false, - }); - expect(screen.queryByText("Delete this experience")).toBeFalsy(); - }); - - it("delete should render when edit is true and be called properly", async () => { - renderExperienceForm({ - userId: mockUserId, - experienceType: "award", - skillsQuery: skillFragments, - edit: true, - }); - // get and open Dialog Component - const deleteButton = screen.getByRole("button", { - name: /delete this experience/i, - }); - expect(deleteButton).toBeTruthy(); - - await user.click(deleteButton); - // get and click on Delete in Dialog - const deleteSubmit = screen.getByRole("button", { name: /delete/i }); - expect(deleteSubmit).toBeTruthy(); - await user.click(deleteSubmit); - - expect(mockClient.executeMutation).toHaveBeenCalled(); - }); -}); diff --git a/apps/web/src/pages/Profile/ExperienceFormPage/ExperienceFormPage.tsx b/apps/web/src/pages/Profile/ExperienceFormPage/ExperienceFormPage.tsx index 7e97e52f730..9b283ed1de8 100644 --- a/apps/web/src/pages/Profile/ExperienceFormPage/ExperienceFormPage.tsx +++ b/apps/web/src/pages/Profile/ExperienceFormPage/ExperienceFormPage.tsx @@ -205,11 +205,95 @@ const ExperienceFormExperience_Fragment = graphql(/* GraphQL */ ` division startDate endDate + employmentCategory { + value + label { + en + fr + } + } + extSizeOfOrganization { + value + label { + en + fr + } + } + extRoleSeniority { + value + label { + en + fr + } + } + govEmploymentType { + value + label { + en + fr + } + } + govPositionType { + value + label { + en + fr + } + } + govContractorRoleSeniority { + value + label { + en + fr + } + } + govContractorType { + value + label { + en + fr + } + } + contractorFirmAgencyName + cafEmploymentType { + value + label { + en + fr + } + } + cafForce { + value + label { + en + fr + } + } + cafRank { + value + label { + en + fr + } + } + classification { + id + group + level + } + department { + id + departmentNumber + name { + en + fr + } + } } } `); -export interface ExperienceFormProps { +interface ExperienceFormProps { edit?: boolean; experienceQuery?: FragmentType; experienceId?: string; diff --git a/apps/web/src/pages/SearchRequests/RequestPage/components/RequestForm.tsx b/apps/web/src/pages/SearchRequests/RequestPage/components/RequestForm.tsx index cf77a476b91..59b2649ba80 100644 --- a/apps/web/src/pages/SearchRequests/RequestPage/components/RequestForm.tsx +++ b/apps/web/src/pages/SearchRequests/RequestPage/components/RequestForm.tsx @@ -43,7 +43,6 @@ import { graphql, FragmentType, getFragment, - PoolStream, } from "@gc-digital-talent/graphql"; import SEO from "~/components/SEO/SEO"; @@ -74,7 +73,7 @@ interface FormValues { qualifiedClassifications?: { sync?: Maybe[]; }; - qualifiedStreams?: ApplicantFilterInput["qualifiedStreams"]; + workStreams?: ApplicantFilterInput["workStreams"]; skills?: { sync?: Maybe[]; }; @@ -131,9 +130,9 @@ const PoolsInFilter_Query = graphql(/* GraphQL */ ` group level } - stream { - value - label { + workStream { + id + name { en fr } @@ -177,9 +176,10 @@ const RequestOptions_Query = graphql(/* GraphQL */ ` fr } } - streams: localizedEnumStrings(enumName: "PoolStream") { - value - label { + workStreams { + id + key + name { en fr } @@ -256,9 +256,14 @@ export const RequestForm = ({ values?.positionType === true ? PoolCandidateSearchPositionType.TeamLead : PoolCandidateSearchPositionType.IndividualContributor; - const qualifiedStreams = applicantFilter?.qualifiedStreams; + const qualifiedStreams = applicantFilter?.workStreams; let community = communities?.find((c) => c.key === "digital"); - if (qualifiedStreams?.includes(PoolStream.AccessInformationPrivacy)) { + const ATIPStream = optionsData?.workStreams?.find( + (workStream) => workStream?.key === "ACCESS_INFORMATION_PRIVACY", + ); + if ( + qualifiedStreams?.some((workStream) => workStream?.id === ATIPStream?.id) + ) { community = communities?.find((c) => c.key === "atip"); } @@ -286,7 +291,13 @@ export const RequestForm = ({ equity: applicantFilter?.equity, languageAbility: applicantFilter?.languageAbility, operationalRequirements: applicantFilter?.operationalRequirements, - qualifiedStreams, + workStreams: { + sync: applicantFilter?.workStreams + ? applicantFilter?.workStreams + ?.filter(notEmpty) + .map(({ id }) => id) + : [], + }, community: { connect: community?.id ?? communities[0].id, }, @@ -386,9 +397,9 @@ export const RequestForm = ({ ), ), ), - qualifiedStreams: unpackMaybes( - applicantFilter?.qualifiedStreams?.map((stream) => - enumInputToLocalizedEnum(stream, optionsData?.streams), + workStreams: unpackMaybes(optionsData?.workStreams).filter((workStream) => + applicantFilter?.workStreams?.some( + (filterStream) => filterStream?.id === workStream?.id, ), ), qualifiedClassifications: diff --git a/apps/web/src/pages/SearchRequests/SearchPage/components/FormFields.tsx b/apps/web/src/pages/SearchRequests/SearchPage/components/FormFields.tsx index cf30e3d9059..fd3cfc5e019 100644 --- a/apps/web/src/pages/SearchRequests/SearchPage/components/FormFields.tsx +++ b/apps/web/src/pages/SearchRequests/SearchPage/components/FormFields.tsx @@ -12,9 +12,15 @@ import { commonMessages, errorMessages, getEmploymentEquityGroup, + getLocalizedName, sortWorkRegion, } from "@gc-digital-talent/i18n"; -import { Classification, Skill, graphql } from "@gc-digital-talent/graphql"; +import { + Classification, + Skill, + WorkStream, + graphql, +} from "@gc-digital-talent/graphql"; import { unpackMaybes } from "@gc-digital-talent/helpers"; import { NullSelection } from "~/types/searchRequest"; @@ -29,13 +35,6 @@ import { classificationAriaLabels, classificationLabels } from "../labels"; const SearchRequestOptions_Query = graphql(/* GraphQL */ ` query SearchRequestOptions { - poolStreams: localizedEnumStrings(enumName: "PoolStream") { - value - label { - en - fr - } - } languageAbilities: localizedEnumStrings(enumName: "LanguageAbility") { value label { @@ -56,9 +55,14 @@ const SearchRequestOptions_Query = graphql(/* GraphQL */ ` interface FormFieldsProps { classifications: Pick[]; skills: Skill[]; + workStreams: WorkStream[]; } -const FormFields = ({ classifications, skills }: FormFieldsProps) => { +const FormFields = ({ + classifications, + skills, + workStreams, +}: FormFieldsProps) => { const intl = useIntl(); const [{ data }] = useQuery({ query: SearchRequestOptions_Query, @@ -74,11 +78,15 @@ const FormFields = ({ classifications, skills }: FormFieldsProps) => { ), })); + const workStreamOptions = workStreams.map((workStream) => ({ + value: workStream.id, + label: getLocalizedName(workStream.name, intl), + })); + const languageAbilityOptions = localizedEnumToOptions( data?.languageAbilities, intl, ); - const streamOptions = localizedEnumToOptions(data?.poolStreams, intl); const sortedWorkRegions = sortWorkRegion(unpackMaybes(data?.workRegions)); const workRegionOptions = localizedEnumToOptions(sortedWorkRegions, intl); @@ -133,7 +141,7 @@ const FormFields = ({ classifications, skills }: FormFieldsProps) => { id: "QJ5uDV", description: "Placeholder for stream filter in search form.", })} - options={streamOptions} + options={workStreamOptions} rules={{ required: intl.formatMessage(errorMessages.required), }} diff --git a/apps/web/src/pages/SearchRequests/SearchPage/components/SearchForm.stories.tsx b/apps/web/src/pages/SearchRequests/SearchPage/components/SearchForm.stories.tsx index 8050c4c49b4..fefdf3afa4b 100644 --- a/apps/web/src/pages/SearchRequests/SearchPage/components/SearchForm.stories.tsx +++ b/apps/web/src/pages/SearchRequests/SearchPage/components/SearchForm.stories.tsx @@ -6,13 +6,10 @@ import { fakeClassifications, fakePools, fakeLocalizedEnum, + fakeWorkStreams, } from "@gc-digital-talent/fake-data"; import { MockGraphqlDecorator } from "@gc-digital-talent/storybook-helpers"; -import { - LanguageAbility, - PoolStream, - WorkRegion, -} from "@gc-digital-talent/graphql"; +import { LanguageAbility, WorkRegion } from "@gc-digital-talent/graphql"; import { SearchForm } from "./SearchForm"; @@ -21,6 +18,7 @@ faker.seed(0); const mockPools = fakePools(10); const poolResponse = fakePools(3); const mockClassifications = fakeClassifications(); +const mockWorkStreams = fakeWorkStreams(); const skills = getStaticSkills(); export default { @@ -29,13 +27,13 @@ export default { args: { pools: mockPools, classifications: mockClassifications, + workStreams: mockWorkStreams, skills, }, } as Meta; const SearchRequestOptions = { data: { - poolStreams: fakeLocalizedEnum(PoolStream), languageAbilities: fakeLocalizedEnum(LanguageAbility), workRegions: fakeLocalizedEnum(WorkRegion), }, diff --git a/apps/web/src/pages/SearchRequests/SearchPage/components/SearchForm.tsx b/apps/web/src/pages/SearchRequests/SearchPage/components/SearchForm.tsx index a6d80cf12ec..68979160bb1 100644 --- a/apps/web/src/pages/SearchRequests/SearchPage/components/SearchForm.tsx +++ b/apps/web/src/pages/SearchRequests/SearchPage/components/SearchForm.tsx @@ -7,16 +7,22 @@ import { ReactNode, useState, useEffect } from "react"; import { Button, Heading, + Link, Loading, Pending, Separator, } from "@gc-digital-talent/ui"; -import { unpackMaybes, notEmpty } from "@gc-digital-talent/helpers"; +import { + unpackMaybes, + notEmpty, + buildMailToUri, +} from "@gc-digital-talent/helpers"; import { graphql, Classification, ApplicantFilterInput, Skill, + WorkStream, } from "@gc-digital-talent/graphql"; import { commonMessages } from "@gc-digital-talent/i18n"; @@ -44,9 +50,14 @@ const styledCount = (chunks: ReactNode) => ( interface SearchFormProps { classifications: Pick[]; skills: Skill[]; + workStreams: WorkStream[]; } -export const SearchForm = ({ classifications, skills }: SearchFormProps) => { +export const SearchForm = ({ + classifications, + skills, + workStreams, +}: SearchFormProps) => { const intl = useIntl(); const navigate = useNavigate(); const paths = useRoutes(); @@ -101,6 +112,53 @@ export const SearchForm = ({ classifications, skills }: SearchFormProps) => { setValue("count", candidateCount); }; + const hireAnApprenticeEmailUri = buildMailToUri( + "edsc.patipa.jumelage.emplois-itapip.job.matching.esdc@hrsdc-rhdcc.gc.ca", + intl.formatMessage({ + defaultMessage: "I'm interested in offering an apprenticeship", + id: "HqtjhD", + description: "Subject line of a manager's email for apprenticeship", + }), + [ + intl.formatMessage({ + defaultMessage: + "To best support you in your journey to hire an IT Apprentice, please let us know if you", + id: "ZKss5S", + description: "Paragraph 1 of a manager's email for apprenticeship", + }), + intl.formatMessage({ + defaultMessage: + "1. are interested in hiring an Apprentice and would like to learn more about the IT Apprenticeship Program for Indigenous Peoples", + id: "ipKAvI", + description: "Paragraph 2 of a manager's email for apprenticeship", + }), + intl.formatMessage({ + defaultMessage: + "2. have reviewed the checklist in the manager’s package and have positions available to hire an IT Apprentice", + id: "18pJdz", + description: "Paragraph 3 of a manager's email for apprenticeship", + }), + intl.formatMessage({ + defaultMessage: "3. Other…", + id: "Fz49kD", + description: "Paragraph 4 of a manager's email for apprenticeship", + }), + intl.formatMessage({ + defaultMessage: + "A team member from the Office of Indigenous Initiatives will be in touch shortly.", + id: "x45gSl", + description: "Paragraph 5 of a manager's email for apprenticeship", + }), + ].join("\n"), + ); + + const selectedClassificationIsIT1 = applicantFilter.qualifiedClassifications + ?.filter(notEmpty) + .some( + (classification) => + classification.group === "IT" && classification.level === 1, + ); + return (
{ "Content displayed in the How To area of the hero section of the Search page.", })}

- +
{ data-h2-display="base(flex)" data-h2-flex-direction="base(column)" > + {selectedClassificationIsIT1 && ( +
+

+ {intl.formatMessage({ + defaultMessage: + "Have you considered hiring an Indigenous IT apprentice?", + id: "kyM6sV", + description: + "Title for IT Apprenticeship Program for Indigenous Peoples search card", + })} +

+

+ {intl.formatMessage({ + defaultMessage: + "The IT Apprenticeship Program for Indigenous Peoples aims to help address and remove barriers Indigenous peoples face when it comes to finding employment in the Government of Canada's digital workforce. Become a hiring partner today and discover how you can strengthen your team with Indigenous IT talent and help build a more inclusive public service. Your participation contributes to the broader goal of inclusion, equity, and reconciliation in Canada.", + id: "ifqj46", + description: + "Paragraph for IT Apprenticeship Program for Indigenous Peoples search card", + })} +

+ +
+ + {intl.formatMessage({ + defaultMessage: "Contact the team", + id: "gJ7CQw", + description: "Link to send an email to the team", + })} + + + {intl.formatMessage({ + defaultMessage: + "Visit the IT Apprenticeship Program for Indigenous Peoples manager page", + id: "zVGzWa", + description: + "Link to visit IT Apprenticeship Program for Indigenous Peoples manager page", + })} + +
+
+ )} {results.map(({ pool, candidateCount: resultsCount }) => ( { const skills = unpackMaybes(data?.skills); const classifications = unpackMaybes(data?.classifications); + const workStreams = unpackMaybes(data?.workStreams); return ( - + ); }; diff --git a/apps/web/src/pages/SearchRequests/SearchPage/components/SearchResultCard.tsx b/apps/web/src/pages/SearchRequests/SearchPage/components/SearchResultCard.tsx index f9ff93c7f09..7c3d5227e37 100644 --- a/apps/web/src/pages/SearchRequests/SearchPage/components/SearchResultCard.tsx +++ b/apps/web/src/pages/SearchRequests/SearchPage/components/SearchResultCard.tsx @@ -22,9 +22,9 @@ const testId = (text: ReactNode) => ( const SearchResultCard_PoolFragment = graphql(/* GraphQL */ ` fragment SearchResultCard_Pool on Pool { id - stream { - value - label { + workStream { + id + name { en fr } @@ -121,7 +121,7 @@ const SearchResultCard = ({ candidateCount, pool }: SearchResultCardProps) => { id={`search_pool_${pool.id}`} > {getShortPoolTitleHtml(intl, { - stream: pool.stream, + workStream: pool.workStream, name: pool.name, publishingGroup: pool.publishingGroup, classification: pool.classification, diff --git a/apps/web/src/pages/SearchRequests/SearchPage/utils.ts b/apps/web/src/pages/SearchRequests/SearchPage/utils.ts index a1edeffa2ba..cda3a7fc2e0 100644 --- a/apps/web/src/pages/SearchRequests/SearchPage/utils.ts +++ b/apps/web/src/pages/SearchRequests/SearchPage/utils.ts @@ -104,7 +104,7 @@ export const dataToFormValues = ( data: ApplicantFilterInput, selectedClassifications?: Maybe[]>, ): FormValues => { - const stream = data?.qualifiedStreams?.find(notEmpty); + const stream = data?.workStreams?.find(notEmpty); return { classification: getCurrentClassification(selectedClassifications), @@ -117,7 +117,7 @@ export const dataToFormValues = ( ], educationRequirement: data.hasDiploma ? "has_diploma" : "no_diploma", skills: data.skills?.filter(notEmpty).map((s) => s.id) ?? [], - stream: stream ?? "", + stream: stream?.id ?? "", locationPreferences: data.locationPreferences?.filter(notEmpty) ?? [], operationalRequirements: data.operationalRequirements?.filter(notEmpty) ?? [], @@ -172,6 +172,6 @@ export const formValuesToData = ( ? durationSelectionToEnum(values.employmentDuration) : undefined, locationPreferences: values.locationPreferences ?? [], - qualifiedStreams: values.stream ? [values.stream] : undefined, + workStreams: values.stream ? [{ id: values.stream }] : undefined, }; }; diff --git a/apps/web/src/pages/SearchRequests/ViewSearchRequestPage/components/SearchRequestCandidatesTable.tsx b/apps/web/src/pages/SearchRequests/ViewSearchRequestPage/components/SearchRequestCandidatesTable.tsx index b40d79e25b2..1159ffff781 100644 --- a/apps/web/src/pages/SearchRequests/ViewSearchRequestPage/components/SearchRequestCandidatesTable.tsx +++ b/apps/web/src/pages/SearchRequests/ViewSearchRequestPage/components/SearchRequestCandidatesTable.tsx @@ -1,24 +1,14 @@ import { useIntl } from "react-intl"; -import omit from "lodash/omit"; -import pick from "lodash/pick"; -import { identity, notEmpty } from "@gc-digital-talent/helpers"; +import { notEmpty, unpackMaybes } from "@gc-digital-talent/helpers"; import { - ApplicantFilterInput, PoolCandidateFilter, ApplicantFilter, - IdInput, - Classification, - ClassificationFilterInput, PoolCandidateSearchInput, PoolCandidateStatus, CandidateSuspendedFilter, CandidateExpiryFilter, } from "@gc-digital-talent/graphql"; -import { - localizedEnumArrayToInput, - localizedEnumToInput, -} from "@gc-digital-talent/i18n"; import PoolCandidatesTable from "~/components/PoolCandidatesTable/PoolCandidatesTable"; import adminMessages from "~/messages/adminMessages"; @@ -33,70 +23,38 @@ function isPoolCandidateFilter( return false; } -function omitIdAndTypename( - x: T, -): Omit { - return omit(x, ["id", "__typename"]) as Omit; -} - -function pickId(x: T): IdInput { - return pick(x, ["id"]); -} - -function classificationToInput(c: Classification): ClassificationFilterInput { - return pick(c, ["group", "level"]); -} - -// Maps each property in ApplicantFilterInput to a function which transforms the matching value from an ApplicantFilter object to the appropriate shape for ApplicantFilterInput. -type MappingType = { - [Property in keyof Omit< - ApplicantFilterInput, - "email" | "name" | "generalSearch" | "skillsIntersectional" - >]: (x: ApplicantFilter[Property]) => ApplicantFilterInput[Property]; -}; - const transformApplicantFilterToPoolCandidateSearchInput = ( applicantFilter: ApplicantFilter, ): PoolCandidateSearchInput => { - // GraphQL will error if an input object includes any unexpected attributes. - // Therefore, transforming ApplicantFilter to ApplicantFilterInput requires omitting any fields not included in the Input type. - const mapping: MappingType = { - equity: omitIdAndTypename, - hasDiploma: identity, - languageAbility: localizedEnumToInput, - locationPreferences: localizedEnumArrayToInput, - operationalRequirements: localizedEnumArrayToInput, - pools: (pools) => pools?.filter(notEmpty).map(pickId), - skills: (skills) => skills?.filter(notEmpty).map(pickId), - positionDuration: identity, - qualifiedStreams: localizedEnumArrayToInput, - community: (community) => (community ? pickId(community) : undefined), - }; - - const emptyFilter: ApplicantFilterInput = {}; - return { - applicantFilter: Object.entries(mapping).reduce( - (applicantFilterInput, filterEntry) => { - const [key, transform] = filterEntry; - const typedKey = key as keyof MappingType; - - // There should be way to get the types to work without using "any", but I'm having trouble. - // I think its safe to fallback on any here because mapping has just been defined, and we can be confident that key and transform line up correctly. - - // eslint-disable-next-line no-param-reassign, @typescript-eslint/no-unsafe-assignment - applicantFilterInput[typedKey] = transform( - // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument - applicantFilter[typedKey] as any, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - ) as any; - return applicantFilterInput; + applicantFilter: { + equity: { + isWoman: applicantFilter.equity?.isWoman ?? undefined, + hasDisability: applicantFilter.equity?.hasDisability, + isIndigenous: applicantFilter.equity?.isIndigenous, + isVisibleMinority: applicantFilter.equity?.isVisibleMinority, }, - emptyFilter, - ), + hasDiploma: applicantFilter?.hasDiploma, + positionDuration: applicantFilter?.positionDuration, + languageAbility: applicantFilter.languageAbility?.value, + locationPreferences: applicantFilter?.locationPreferences + ?.filter(notEmpty) + .map((workRegion) => workRegion?.value), + operationalRequirements: applicantFilter?.operationalRequirements + ?.filter(notEmpty) + .map((req) => req?.value), + pools: unpackMaybes(applicantFilter.pools).map(({ id }) => ({ id })), + skills: unpackMaybes(applicantFilter.skills).map(({ id }) => ({ id })), + workStreams: unpackMaybes(applicantFilter.workStreams).map(({ id }) => ({ + id, + })), + community: applicantFilter?.community?.id + ? { id: applicantFilter.community.id } + : undefined, + }, appliedClassifications: applicantFilter.qualifiedClassifications ?.filter(notEmpty) - .map(classificationToInput), + .map(({ group, level }) => ({ group, level })), poolCandidateStatus: [ PoolCandidateStatus.QualifiedAvailable, PoolCandidateStatus.PlacedCasual, diff --git a/apps/web/src/pages/SearchRequests/ViewSearchRequestPage/components/ViewSearchRequest.tsx b/apps/web/src/pages/SearchRequests/ViewSearchRequestPage/components/ViewSearchRequest.tsx index 645a85a3256..d378c707e7c 100644 --- a/apps/web/src/pages/SearchRequests/ViewSearchRequestPage/components/ViewSearchRequest.tsx +++ b/apps/web/src/pages/SearchRequests/ViewSearchRequestPage/components/ViewSearchRequest.tsx @@ -296,9 +296,9 @@ const ViewSearchRequest_SearchRequestFragment = graphql(/* GraphQL */ ` group level } - stream { - value - label { + workStream { + id + name { en fr } @@ -367,9 +367,9 @@ const ViewSearchRequest_SearchRequestFragment = graphql(/* GraphQL */ ` en fr } - stream { - value - label { + workStream { + id + name { en fr } @@ -389,9 +389,9 @@ const ViewSearchRequest_SearchRequestFragment = graphql(/* GraphQL */ ` group level } - qualifiedStreams { - value - label { + workStreams { + id + name { en fr } diff --git a/apps/web/src/pages/Skills/UpdateUserSkillPage.tsx b/apps/web/src/pages/Skills/UpdateUserSkillPage.tsx index 8cf6554ba01..ed1badd079f 100644 --- a/apps/web/src/pages/Skills/UpdateUserSkillPage.tsx +++ b/apps/web/src/pages/Skills/UpdateUserSkillPage.tsx @@ -186,6 +186,90 @@ export const UpdateUserSkillExperience_Fragment = graphql(/* GraphQL */ ` division startDate endDate + employmentCategory { + value + label { + en + fr + } + } + extSizeOfOrganization { + value + label { + en + fr + } + } + extRoleSeniority { + value + label { + en + fr + } + } + govEmploymentType { + value + label { + en + fr + } + } + govPositionType { + value + label { + en + fr + } + } + govContractorRoleSeniority { + value + label { + en + fr + } + } + govContractorType { + value + label { + en + fr + } + } + contractorFirmAgencyName + cafEmploymentType { + value + label { + en + fr + } + } + cafForce { + value + label { + en + fr + } + } + cafRank { + value + label { + en + fr + } + } + classification { + id + group + level + } + department { + id + departmentNumber + name { + en + fr + } + } } } `); @@ -278,6 +362,90 @@ export const UpdateUserSkill_Fragment = graphql(/* GraphQL */ ` division startDate endDate + employmentCategory { + value + label { + en + fr + } + } + extSizeOfOrganization { + value + label { + en + fr + } + } + extRoleSeniority { + value + label { + en + fr + } + } + govEmploymentType { + value + label { + en + fr + } + } + govPositionType { + value + label { + en + fr + } + } + govContractorRoleSeniority { + value + label { + en + fr + } + } + govContractorType { + value + label { + en + fr + } + } + contractorFirmAgencyName + cafEmploymentType { + value + label { + en + fr + } + } + cafForce { + value + label { + en + fr + } + } + cafRank { + value + label { + en + fr + } + } + classification { + id + group + level + } + department { + id + departmentNumber + name { + en + fr + } + } } skills { id diff --git a/apps/web/src/pages/SupportPage/components/SupportForm/SupportForm.tsx b/apps/web/src/pages/SupportPage/components/SupportForm/SupportForm.tsx index bcce845b14e..0ce1e71ad00 100644 --- a/apps/web/src/pages/SupportPage/components/SupportForm/SupportForm.tsx +++ b/apps/web/src/pages/SupportPage/components/SupportForm/SupportForm.tsx @@ -2,7 +2,7 @@ // Note: Disable camelcase since variables are being used by API import { FormProvider, SubmitHandler, useForm } from "react-hook-form"; import { defineMessage, useIntl } from "react-intl"; -import { useLocation, Location } from "react-router"; +import { useLocation, Location, useSearchParams } from "react-router"; import { useQuery } from "urql"; import { ReactNode, useState } from "react"; @@ -50,6 +50,15 @@ const anchorTag = (chunks: ReactNode) => ( {chunks} ); +const availableSubjects = ["bug", "feedback", "question"]; +function defaultSubject(subject?: string | null): string { + if (subject && availableSubjects.includes(subject)) { + return subject; + } + + return ""; +} + const SupportFormSuccess = ({ onFormToggle }: SupportFormSuccessProps) => { const intl = useIntl(); return ( @@ -118,10 +127,13 @@ const SupportForm = ({ }: SupportFormProps) => { const intl = useIntl(); const location = useLocation() as Location; + const [params] = useSearchParams(); const previousUrl = location?.state?.referrer ?? document?.referrer ?? ""; const userAgent = window?.navigator.userAgent ?? ""; const methods = useForm({ defaultValues: { + subject: defaultSubject(params.get("subject")), + description: params.get("description") ?? "", user_id: currentUser?.id ?? "", name: currentUser ? getFullNameLabel(currentUser.firstName, currentUser.lastName, intl) diff --git a/apps/web/src/pages/Teams/TeamMembersPage/TeamMembersPage.tsx b/apps/web/src/pages/Teams/TeamMembersPage/TeamMembersPage.tsx index d63a480996a..db46cdd2c74 100644 --- a/apps/web/src/pages/Teams/TeamMembersPage/TeamMembersPage.tsx +++ b/apps/web/src/pages/Teams/TeamMembersPage/TeamMembersPage.tsx @@ -124,8 +124,8 @@ const TeamMembers = ({ teamQuery }: TeamMembersProps) => { }, nullMessage: { description: intl.formatMessage({ - defaultMessage: 'Use the "Add new member" button to get started.', - id: "SfbDLA", + defaultMessage: 'Use the "Add member" button to get started.', + id: "s57oJd", description: "Instructions for adding a member to a team.", }), }, diff --git a/apps/web/src/pages/Teams/TeamMembersPage/components/AddTeamMemberDialog.tsx b/apps/web/src/pages/Teams/TeamMembersPage/components/AddTeamMemberDialog.tsx index 38da31c72fa..e3e6f2bf5eb 100644 --- a/apps/web/src/pages/Teams/TeamMembersPage/components/AddTeamMemberDialog.tsx +++ b/apps/web/src/pages/Teams/TeamMembersPage/components/AddTeamMemberDialog.tsx @@ -113,21 +113,25 @@ AddTeamMemberDialogProps) => { ), })); - const label = intl.formatMessage({ - defaultMessage: "Add new member", - id: "+e2nr6", - description: "Label for the add member to team form", - }); - return ( - {label} + + {intl.formatMessage({ + defaultMessage: "Add member", + id: "9vluO2", + description: "Header for the add member to team form", + })} +

{intl.formatMessage({ @@ -206,7 +210,11 @@ AddTeamMemberDialogProps) => { + ) : ( + <> + + {separatorSpan} + ); case "link": - return ( + return index + 1 === metadataLength ? ( { > {children} + ) : ( + <> + + {children} + + {separatorSpan} + ); default: return null; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c85cbbcf30b..1491ea2a3ac 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -115,8 +115,8 @@ importers: specifier: ^3.3.4 version: 3.3.4(tslib@2.8.0) '@tanstack/react-table': - specifier: ^8.20.5 - version: 8.20.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^8.20.6 + version: 8.20.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) dataloader: specifier: ^2.2.3 version: 2.2.3 @@ -124,11 +124,11 @@ importers: specifier: ^3.6.0 version: 3.6.0 framer-motion: - specifier: ^11.14.1 - version: 11.14.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^11.15.0 + version: 11.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) graphql: - specifier: ^16.9.0 - version: 16.9.0 + specifier: ^16.10.0 + version: 16.10.0 lodash: specifier: ^4.17.21 version: 4.17.21 @@ -142,8 +142,8 @@ importers: specifier: ^2.0.5 version: 2.0.5(react@18.3.1) react-hook-form: - specifier: ^7.54.0 - version: 7.54.0(react@18.3.1) + specifier: ^7.54.1 + version: 7.54.1(react@18.3.1) react-intl: specifier: ^7.0.4 version: 7.0.4(react@18.3.1)(typescript@5.7.2) @@ -155,7 +155,7 @@ importers: version: 2.15.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) urql: specifier: ^4.2.1 - version: 4.2.1(@urql/core@5.1.0(graphql@16.9.0))(react@18.3.1) + version: 4.2.1(@urql/core@5.1.0(graphql@16.10.0))(react@18.3.1) devDependencies: '@faker-js/faker': specifier: ^9.3.0 @@ -213,7 +213,7 @@ importers: version: 18.3.1 '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@6.0.3(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5)) + version: 4.3.4(vite@6.0.4(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5)) dotenv: specifier: ^16.4.7 version: 16.4.7 @@ -248,14 +248,14 @@ importers: specifier: ^5.7.2 version: 5.7.2 vite: - specifier: ^6.0.3 - version: 6.0.3(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5) + specifier: ^6.0.4 + version: 6.0.4(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5) vite-plugin-compression2: specifier: ^1.3.3 - version: 1.3.3(rollup@4.27.4)(vite@6.0.3(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5)) + version: 1.3.3(rollup@4.27.4)(vite@6.0.4(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5)) vite-plugin-html: specifier: ^3.2.2 - version: 3.2.2(vite@6.0.3(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5)) + version: 3.2.2(vite@6.0.4(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5)) packages/app-insights: dependencies: @@ -319,7 +319,7 @@ importers: version: 7.0.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) urql: specifier: ^4.2.1 - version: 4.2.1(@urql/core@5.1.0(graphql@16.9.0))(react@18.3.1) + version: 4.2.1(@urql/core@5.1.0(graphql@16.10.0))(react@18.3.1) devDependencies: '@gc-digital-talent/eslint-config': specifier: workspace:* @@ -362,13 +362,13 @@ importers: version: link:../toast '@urql/core': specifier: ^5.1.0 - version: 5.1.0(graphql@16.9.0) + version: 5.1.0(graphql@16.10.0) '@urql/exchange-auth': specifier: ^2.2.0 - version: 2.2.0(@urql/core@5.1.0(graphql@16.9.0)) + version: 2.2.0(@urql/core@5.1.0(graphql@16.10.0)) graphql: - specifier: ^16.9.0 - version: 16.9.0 + specifier: ^16.10.0 + version: 16.10.0 jwt-decode: specifier: ^4.0.0 version: 4.0.0 @@ -380,7 +380,7 @@ importers: version: 7.0.4(react@18.3.1)(typescript@5.7.2) urql: specifier: ^4.2.1 - version: 4.2.1(@urql/core@5.1.0(graphql@16.9.0))(react@18.3.1) + version: 4.2.1(@urql/core@5.1.0(graphql@16.10.0))(react@18.3.1) devDependencies: '@gc-digital-talent/eslint-config': specifier: workspace:* @@ -596,22 +596,22 @@ importers: version: 2.2.0(react@18.3.1) '@hookform/error-message': specifier: ^2.0.1 - version: 2.0.1(react-dom@18.3.1(react@18.3.1))(react-hook-form@7.54.0(react@18.3.1))(react@18.3.1) + version: 2.0.1(react-dom@18.3.1(react@18.3.1))(react-hook-form@7.54.1(react@18.3.1))(react@18.3.1) '@tiptap/extension-character-count': - specifier: ^2.10.3 - version: 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3) + specifier: ^2.10.4 + version: 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))(@tiptap/pm@2.10.4) '@tiptap/extension-heading': - specifier: ^2.10.3 - version: 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) + specifier: ^2.10.4 + version: 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4)) '@tiptap/extension-link': - specifier: ^2.10.3 - version: 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3) + specifier: ^2.10.4 + version: 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))(@tiptap/pm@2.10.4) '@tiptap/react': - specifier: ^2.10.3 - version: 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^2.10.4 + version: 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))(@tiptap/pm@2.10.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@tiptap/starter-kit': - specifier: ^2.10.3 - version: 2.10.3 + specifier: ^2.10.4 + version: 2.10.4 date-fns: specifier: ^3.6.0 version: 3.6.0 @@ -619,8 +619,8 @@ importers: specifier: ^9.0.8 version: 9.0.8(react@18.3.1) framer-motion: - specifier: ^11.14.1 - version: 11.14.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^11.15.0 + version: 11.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) lodash: specifier: ^4.17.21 version: 4.17.21 @@ -686,8 +686,8 @@ importers: specifier: ^18.3.1 version: 18.3.1 react-hook-form: - specifier: ^7.54.0 - version: 7.54.0(react@18.3.1) + specifier: ^7.54.1 + version: 7.54.1(react@18.3.1) react-intl: specifier: ^7.0.4 version: 7.0.4(react@18.3.1)(typescript@5.7.2) @@ -702,16 +702,16 @@ importers: devDependencies: '@graphql-codegen/cli': specifier: ^5.0.3 - version: 5.0.3(@parcel/watcher@2.5.0)(@types/node@22.10.2)(graphql@16.9.0)(typescript@5.7.2) + version: 5.0.3(@parcel/watcher@2.5.0)(@types/node@22.10.2)(graphql@16.10.0)(typescript@5.7.2) '@graphql-codegen/client-preset': specifier: ^4.5.1 - version: 4.5.1(graphql@16.9.0) + version: 4.5.1(graphql@16.10.0) '@parcel/watcher': specifier: ^2.5.0 version: 2.5.0 graphql: - specifier: ^16.9.0 - version: 16.9.0 + specifier: ^16.10.0 + version: 16.10.0 tsconfig: specifier: workspace:* version: link:../tsconfig @@ -720,7 +720,7 @@ importers: version: 5.7.2 urql: specifier: ^4.2.1 - version: 4.2.1(@urql/core@5.1.0(graphql@16.9.0))(react@18.3.1) + version: 4.2.1(@urql/core@5.1.0(graphql@16.10.0))(react@18.3.1) packages/helpers: dependencies: @@ -731,8 +731,8 @@ importers: specifier: workspace:* version: link:../storage graphql: - specifier: ^16.9.0 - version: 16.9.0 + specifier: ^16.10.0 + version: 16.10.0 lodash: specifier: ^4.17.21 version: 4.17.21 @@ -741,7 +741,7 @@ importers: version: 18.3.1 urql: specifier: ^4.2.1 - version: 4.2.1(@urql/core@5.1.0(graphql@16.9.0))(react@18.3.1) + version: 4.2.1(@urql/core@5.1.0(graphql@16.10.0))(react@18.3.1) devDependencies: '@gc-digital-talent/eslint-config': specifier: workspace:* @@ -796,8 +796,8 @@ importers: specifier: ^4.1.0 version: 4.1.0 json-stable-stringify: - specifier: ^1.1.1 - version: 1.1.1 + specifier: ^1.2.0 + version: 1.2.0 react: specifier: ^18.3.1 version: 18.3.1 @@ -941,16 +941,16 @@ importers: version: 8.4.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.7(prettier@3.4.2))(typescript@5.7.2) '@urql/core': specifier: ^5.1.0 - version: 5.1.0(graphql@16.9.0) + version: 5.1.0(graphql@16.10.0) chromatic: specifier: ^11.20.2 version: 11.20.2 framer-motion: - specifier: ^11.14.1 - version: 11.14.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^11.15.0 + version: 11.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) graphql: - specifier: ^16.9.0 - version: 16.9.0 + specifier: ^16.10.0 + version: 16.10.0 lodash: specifier: ^4.17.21 version: 4.17.21 @@ -962,7 +962,7 @@ importers: version: 7.0.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) urql: specifier: ^4.2.1 - version: 4.2.1(@urql/core@5.1.0(graphql@16.9.0))(react@18.3.1) + version: 4.2.1(@urql/core@5.1.0(graphql@16.10.0))(react@18.3.1) wonka: specifier: ^6.3.4 version: 6.3.4 @@ -984,13 +984,13 @@ importers: version: 8.4.7(storybook@8.4.7(prettier@3.4.2)) '@storybook/builder-vite': specifier: ^8.4.7 - version: 8.4.7(storybook@8.4.7(prettier@3.4.2))(vite@6.0.3(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5)) + version: 8.4.7(storybook@8.4.7(prettier@3.4.2))(vite@6.0.4(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5)) '@storybook/preview-api': specifier: ^8.4.7 version: 8.4.7(storybook@8.4.7(prettier@3.4.2)) '@storybook/react-vite': specifier: ^8.4.7 - version: 8.4.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.27.4)(storybook@8.4.7(prettier@3.4.2))(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5)) + version: 8.4.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.27.4)(storybook@8.4.7(prettier@3.4.2))(typescript@5.7.2)(vite@6.0.4(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5)) '@storybook/types': specifier: ^8.4.7 version: 8.4.7(storybook@8.4.7(prettier@3.4.2)) @@ -1104,71 +1104,71 @@ importers: specifier: ^2.2.0 version: 2.2.0(react@18.3.1) '@radix-ui/react-accordion': - specifier: ^1.2.1 - version: 1.2.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^1.2.2 + version: 1.2.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-alert-dialog': - specifier: ^1.1.2 - version: 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^1.1.4 + version: 1.1.4(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-collapsible': - specifier: ^1.1.1 - version: 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-dialog': specifier: ^1.1.2 version: 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-dialog': + specifier: ^1.1.4 + version: 1.1.4(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-dropdown-menu': - specifier: ^2.1.2 - version: 2.1.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^2.1.4 + version: 2.1.4(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-navigation-menu': - specifier: ^1.2.1 - version: 1.2.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^1.2.3 + version: 1.2.3(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-scroll-area': - specifier: ^1.2.1 - version: 1.2.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^1.2.2 + version: 1.2.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-separator': - specifier: ^1.1.0 - version: 1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': - specifier: ^1.1.0 - version: 1.1.0(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-switch': specifier: ^1.1.1 version: 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': + specifier: ^1.1.1 + version: 1.1.1(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/react-switch': + specifier: ^1.1.2 + version: 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-tabs': + specifier: ^1.1.2 + version: 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-toggle': specifier: ^1.1.1 version: 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-toggle': - specifier: ^1.1.0 - version: 1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-toggle-group': - specifier: ^1.1.0 - version: 1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^1.1.1 + version: 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) chromatic: specifier: ^11.20.2 version: 11.20.2 framer-motion: - specifier: ^11.14.1 - version: 11.14.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^11.15.0 + version: 11.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) lodash: specifier: ^4.17.21 version: 4.17.21 react-csv-downloader: - specifier: ^3.1.1 - version: 3.1.1(react@18.3.1) + specifier: ^3.2.0 + version: 3.2.0(react@18.3.1) react-dom: specifier: ^18.2.0 version: 18.3.1(react@18.3.1) react-focus-lock: - specifier: ^2.13.2 - version: 2.13.2(@types/react@18.3.13)(react@18.3.1) + specifier: ^2.13.5 + version: 2.13.5(@types/react@18.3.13)(react@18.3.1) react-remove-scroll: - specifier: ^2.6.0 - version: 2.6.0(@types/react@18.3.13)(react@18.3.1) + specifier: ^2.6.2 + version: 2.6.2(@types/react@18.3.13)(react@18.3.1) react-router: specifier: ^7.0.2 version: 7.0.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) urql: specifier: ^4.2.1 - version: 4.2.1(@urql/core@5.1.0(graphql@16.9.0))(react@18.3.1) + version: 4.2.1(@urql/core@5.1.0(graphql@16.10.0))(react@18.3.1) devDependencies: '@faker-js/faker': specifier: ^9.3.0 @@ -1618,10 +1618,6 @@ packages: resolution: {integrity: sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==} engines: {node: '>=6.9.0'} - '@babel/runtime@7.25.4': - resolution: {integrity: sha512-DSgLeL/FNcpXuzav5wfYvHCGvynXkJbn3Zvc3823AEe9nPwW9IK4UoCSS5yGymmQzN0pCPvivtgS6/8U2kkm1w==} - engines: {node: '>=6.9.0'} - '@babel/runtime@7.26.0': resolution: {integrity: sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==} engines: {node: '>=6.9.0'} @@ -2612,11 +2608,11 @@ packages: '@radix-ui/number@1.1.0': resolution: {integrity: sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==} - '@radix-ui/primitive@1.1.0': - resolution: {integrity: sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==} + '@radix-ui/primitive@1.1.1': + resolution: {integrity: sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==} - '@radix-ui/react-accordion@1.2.1': - resolution: {integrity: sha512-bg/l7l5QzUjgsh8kjwDFommzAshnUsuVMV5NM56QVCm+7ZckYdd9P/ExR8xG/Oup0OajVxNLaHJ1tb8mXk+nzQ==} + '@radix-ui/react-accordion@1.2.2': + resolution: {integrity: sha512-b1oh54x4DMCdGsB4/7ahiSrViXxaBwRPotiZNnYXjLha9vfuURSAZErki6qjDoSIV0eXx5v57XnTGVtGwnfp2g==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2628,8 +2624,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-alert-dialog@1.1.2': - resolution: {integrity: sha512-eGSlLzPhKO+TErxkiGcCZGuvbVMnLA1MTnyBksGOeGRGkxHiiJUujsjmNTdWTm4iHVSRaUao9/4Ur671auMghQ==} + '@radix-ui/react-alert-dialog@1.1.4': + resolution: {integrity: sha512-A6Kh23qZDLy3PSU4bh2UJZznOrUdHImIXqF8YtUa6CN73f8EOO9XlXSCd9IHyPvIquTaa/kwaSWzZTtUvgXVGw==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2641,8 +2637,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-arrow@1.1.0': - resolution: {integrity: sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==} + '@radix-ui/react-arrow@1.1.1': + resolution: {integrity: sha512-NaVpZfmv8SKeZbn4ijN2V3jlHA9ngBG16VnIIm22nUR0Yk8KUALyBxT3KYEUnNuch9sTE8UTsS3whzBgKOL30w==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2654,8 +2650,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-collapsible@1.1.1': - resolution: {integrity: sha512-1///SnrfQHJEofLokyczERxQbWfCGQlQ2XsCZMucVs6it+lq9iw4vXy+uDn1edlb58cOZOWSldnfPAYcT4O/Yg==} + '@radix-ui/react-collapsible@1.1.2': + resolution: {integrity: sha512-PliMB63vxz7vggcyq0IxNYk8vGDrLXVWw4+W4B8YnwI1s18x7YZYqlG9PLX7XxAJUi0g2DxP4XKJMFHh/iVh9A==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2667,8 +2663,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-collection@1.1.0': - resolution: {integrity: sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==} + '@radix-ui/react-collection@1.1.1': + resolution: {integrity: sha512-LwT3pSho9Dljg+wY2KN2mrrh6y3qELfftINERIzBUO9e0N+t0oMTyn3k9iv+ZqgrwGkRnLpNJrsMv9BZlt2yuA==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2680,17 +2676,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-compose-refs@1.1.0': - resolution: {integrity: sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-context@1.1.0': - resolution: {integrity: sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==} + '@radix-ui/react-compose-refs@1.1.1': + resolution: {integrity: sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==} peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -2707,8 +2694,8 @@ packages: '@types/react': optional: true - '@radix-ui/react-dialog@1.1.2': - resolution: {integrity: sha512-Yj4dZtqa2o+kG61fzB0H2qUvmwBA2oyQroGLyNtBj1beo1khoQ3q1a2AO8rrQYjd8256CO9+N8L9tvsS+bnIyA==} + '@radix-ui/react-dialog@1.1.4': + resolution: {integrity: sha512-Ur7EV1IwQGCyaAuyDRiOLA5JIUZxELJljF+MbM/2NC0BYwfuRrbpS30BiQBJrVruscgUkieKkqXYDOoByaxIoA==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2729,8 +2716,8 @@ packages: '@types/react': optional: true - '@radix-ui/react-dismissable-layer@1.1.1': - resolution: {integrity: sha512-QSxg29lfr/xcev6kSz7MAlmDnzbP1eI/Dwn3Tp1ip0KT5CUELsxkekFEMVBEoykI3oV39hKT4TKZzBNMbcTZYQ==} + '@radix-ui/react-dismissable-layer@1.1.3': + resolution: {integrity: sha512-onrWn/72lQoEucDmJnr8uczSNTujT0vJnA/X5+3AkChVPowr8n1yvIKIabhWyMQeMvvmdpsvcyDqx3X1LEXCPg==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2742,8 +2729,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-dropdown-menu@2.1.2': - resolution: {integrity: sha512-GVZMR+eqK8/Kes0a36Qrv+i20bAPXSn8rCBTHx30w+3ECnR5o3xixAlqcVaYvLeyKUsm0aqyhWfmUcqufM8nYA==} + '@radix-ui/react-dropdown-menu@2.1.4': + resolution: {integrity: sha512-iXU1Ab5ecM+yEepGAWK8ZhMyKX4ubFdCNtol4sT9D0OVErG9PNElfx3TQhjw7n7BC5nFVz68/5//clWy+8TXzA==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2764,8 +2751,8 @@ packages: '@types/react': optional: true - '@radix-ui/react-focus-scope@1.1.0': - resolution: {integrity: sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==} + '@radix-ui/react-focus-scope@1.1.1': + resolution: {integrity: sha512-01omzJAYRxXdG2/he/+xy+c8a8gCydoQ1yOxnWNcRhrrBW5W+RQJ22EK1SaO8tb3WoUsuEw7mJjBozPzihDFjA==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2786,8 +2773,8 @@ packages: '@types/react': optional: true - '@radix-ui/react-menu@2.1.2': - resolution: {integrity: sha512-lZ0R4qR2Al6fZ4yCCZzu/ReTFrylHFxIqy7OezIpWF4bL0o9biKo0pFIvkaew3TyZ9Fy5gYVrR5zCGZBVbO1zg==} + '@radix-ui/react-menu@2.1.4': + resolution: {integrity: sha512-BnOgVoL6YYdHAG6DtXONaR29Eq4nvbi8rutrV/xlr3RQCMMb3yqP85Qiw/3NReozrSW+4dfLkK+rc1hb4wPU/A==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2799,8 +2786,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-navigation-menu@1.2.1': - resolution: {integrity: sha512-egDo0yJD2IK8L17gC82vptkvW1jLeni1VuqCyzY727dSJdk5cDjINomouLoNk8RVF7g2aNIfENKWL4UzeU9c8Q==} + '@radix-ui/react-navigation-menu@1.2.3': + resolution: {integrity: sha512-IQWAsQ7dsLIYDrn0WqPU+cdM7MONTv9nqrLVYoie3BPiabSfUVDe6Fr+oEt0Cofsr9ONDcDe9xhmJbL1Uq1yKg==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2812,8 +2799,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-popper@1.2.0': - resolution: {integrity: sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==} + '@radix-ui/react-popper@1.2.1': + resolution: {integrity: sha512-3kn5Me69L+jv82EKRuQCXdYyf1DqHwD2U/sxoNgBGCB7K9TRc3bQamQ+5EPM9EvyPdli0W41sROd+ZU1dTCztw==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2825,8 +2812,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-portal@1.1.2': - resolution: {integrity: sha512-WeDYLGPxJb/5EGBoedyJbT0MpoULmwnIPMJMSldkuiMsBAv7N1cRdsTWZWht9vpPOiN3qyiGAtbK2is47/uMFg==} + '@radix-ui/react-portal@1.1.3': + resolution: {integrity: sha512-NciRqhXnGojhT93RPyDaMPfLH3ZSl4jjIFbZQ1b/vxvZEdHsBZ49wP9w8L3HzUQwep01LcWtkUvm0OVB5JAHTw==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2838,8 +2825,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-presence@1.1.1': - resolution: {integrity: sha512-IeFXVi4YS1K0wVZzXNrbaaUvIJ3qdY+/Ih4eHFhWA9SwGR9UDX7Ck8abvL57C4cv3wwMvUE0OG69Qc3NCcTe/A==} + '@radix-ui/react-presence@1.1.2': + resolution: {integrity: sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2851,8 +2838,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-primitive@2.0.0': - resolution: {integrity: sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==} + '@radix-ui/react-primitive@2.0.1': + resolution: {integrity: sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2864,8 +2851,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-roving-focus@1.1.0': - resolution: {integrity: sha512-EA6AMGeq9AEeQDeSH0aZgG198qkfHSbvWTf1HvoDmOB5bBG/qTxjYMWUKMnYiV6J/iP/J8MEFSuB2zRU2n7ODA==} + '@radix-ui/react-roving-focus@1.1.1': + resolution: {integrity: sha512-QE1RoxPGJ/Nm8Qmk0PxP8ojmoaS67i0s7hVssS7KuI2FQoc/uzVlZsqKfQvxPE6D8hICCPHJ4D88zNhT3OOmkw==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2877,8 +2864,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-scroll-area@1.2.1': - resolution: {integrity: sha512-FnM1fHfCtEZ1JkyfH/1oMiTcFBQvHKl4vD9WnpwkLgtF+UmnXMCad6ECPTaAjcDjam+ndOEJWgHyKDGNteWSHw==} + '@radix-ui/react-scroll-area@1.2.2': + resolution: {integrity: sha512-EFI1N/S3YxZEW/lJ/H1jY3njlvTd8tBmgKEn4GHi51+aMm94i6NmAJstsm5cu3yJwYqYc93gpCPm21FeAbFk6g==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2890,8 +2877,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-separator@1.1.0': - resolution: {integrity: sha512-3uBAs+egzvJBDZAzvb/n4NxxOYpnspmWxO2u5NbZ8Y6FM/NdrGSF9bop3Cf6F6C71z1rTSn8KV0Fo2ZVd79lGA==} + '@radix-ui/react-separator@1.1.1': + resolution: {integrity: sha512-RRiNRSrD8iUiXriq/Y5n4/3iE8HzqgLHsusUSg5jVpU2+3tqcUFPJXHDymwEypunc2sWxDUS3UC+rkZRlHedsw==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2903,8 +2890,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-slot@1.1.0': - resolution: {integrity: sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==} + '@radix-ui/react-slot@1.1.1': + resolution: {integrity: sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==} peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -2912,8 +2899,8 @@ packages: '@types/react': optional: true - '@radix-ui/react-switch@1.1.1': - resolution: {integrity: sha512-diPqDDoBcZPSicYoMWdWx+bCPuTRH4QSp9J+65IvtdS0Kuzt67bI6n32vCj8q6NZmYW/ah+2orOtMwcX5eQwIg==} + '@radix-ui/react-switch@1.1.2': + resolution: {integrity: sha512-zGukiWHjEdBCRyXvKR6iXAQG6qXm2esuAD6kDOi9Cn+1X6ev3ASo4+CsYaD6Fov9r/AQFekqnD/7+V0Cs6/98g==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2925,8 +2912,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-tabs@1.1.1': - resolution: {integrity: sha512-3GBUDmP2DvzmtYLMsHmpA1GtR46ZDZ+OreXM/N+kkQJOPIgytFWWTfDQmBQKBvaFS0Vno0FktdbVzN28KGrMdw==} + '@radix-ui/react-tabs@1.1.2': + resolution: {integrity: sha512-9u/tQJMcC2aGq7KXpGivMm1mgq7oRJKXphDwdypPd/j21j/2znamPU8WkXgnhUaTrSFNIt8XhOyCAupg8/GbwQ==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2938,8 +2925,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-toggle-group@1.1.0': - resolution: {integrity: sha512-PpTJV68dZU2oqqgq75Uzto5o/XfOVgkrJ9rulVmfTKxWp3HfUjHE6CP/WLRR4AzPX9HWxw7vFow2me85Yu+Naw==} + '@radix-ui/react-toggle-group@1.1.1': + resolution: {integrity: sha512-OgDLZEA30Ylyz8YSXvnGqIHtERqnUt1KUYTKdw/y8u7Ci6zGiJfXc02jahmcSNK3YcErqioj/9flWC9S1ihfwg==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2951,8 +2938,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-toggle@1.1.0': - resolution: {integrity: sha512-gwoxaKZ0oJ4vIgzsfESBuSgJNdc0rv12VhHgcqN0TEJmmZixXG/2XpsLK8kzNWYcnaoRIEEQc0bEi3dIvdUpjw==} + '@radix-ui/react-toggle@1.1.1': + resolution: {integrity: sha512-i77tcgObYr743IonC1hrsnnPmszDRn8p+EGUsUt+5a/JFn28fxaM88Py6V2mc8J5kELMWishI0rLnuGLFD/nnQ==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -3027,8 +3014,8 @@ packages: '@types/react': optional: true - '@radix-ui/react-visually-hidden@1.1.0': - resolution: {integrity: sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ==} + '@radix-ui/react-visually-hidden@1.1.1': + resolution: {integrity: sha512-vVfA2IZ9q/J+gEamvj761Oq1FpWgCDaNOOIfbPVp2MVPLEomUr5+Vf7kJGwQ24YxZSlQVar7Bes8kyTo5Dshpg==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -3333,8 +3320,8 @@ packages: peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@tanstack/react-table@8.20.5': - resolution: {integrity: sha512-WEHopKw3znbUZ61s9i0+i9g8drmDo6asTWbrQh8Us63DAk/M0FkmIqERew6P71HI75ksZ2Pxyuf4vvKh9rAkiA==} + '@tanstack/react-table@8.20.6': + resolution: {integrity: sha512-w0jluT718MrOKthRcr2xsjqzx+oEM7B7s/XXyfs19ll++hlId3fjTm+B2zrR3ijpANpkzBAr15j1XGVOMxpggQ==} engines: {node: '>=12'} peerDependencies: react: '>=16.8' @@ -3373,148 +3360,148 @@ packages: peerDependencies: '@testing-library/dom': '>=7.21.4' - '@tiptap/core@2.10.3': - resolution: {integrity: sha512-wAG/0/UsLeZLmshWb6rtWNXKJftcmnned91/HLccHVQAuQZ1UWH+wXeQKu/mtodxEO7JcU2mVPR9mLGQkK0McQ==} + '@tiptap/core@2.10.4': + resolution: {integrity: sha512-fExFRTRgb6MSpg2VvR5qO2dPTQAZWuUoU4UsBCurIVcPWcyVv4FG1YzgMyoLDKy44rebFtwUGJbfU9NzX7Q/bA==} peerDependencies: '@tiptap/pm': ^2.7.0 - '@tiptap/extension-blockquote@2.10.3': - resolution: {integrity: sha512-u9Mq4r8KzoeGVT8ms6FQDIMN95dTh3TYcT7fZpwcVM96mIl2Oyt+Bk66mL8z4zuFptfRI57Cu9QdnHEeILd//w==} + '@tiptap/extension-blockquote@2.10.4': + resolution: {integrity: sha512-4JSwAM3B92YWvGzu/Vd5rovPrCGwLSaSLD5rxcLyfxLSrTDQd3n7lp78pzVgGhunVECzaGF5A0ByWWpEyS0a3w==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-bold@2.10.3': - resolution: {integrity: sha512-xnF1tS2BsORenr11qyybW120gHaeHKiKq+ZOP14cGA0MsriKvWDnaCSocXP/xMEYHy7+2uUhJ0MsKkHVj4bPzQ==} + '@tiptap/extension-bold@2.10.4': + resolution: {integrity: sha512-SdO4oFQKaERCGfwOc1CLYQRtThENam2KWfWmvpsymknokt5qYzU57ft0SE1HQV9vVYEzZ9HrWIgv2xrgu0g9kg==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-bubble-menu@2.10.3': - resolution: {integrity: sha512-e9a4yMjQezuKy0rtyyzxbV2IAE1bm1PY3yoZEFrcaY0o47g1CMUn2Hwe+9As2HdntEjQpWR7NO1mZeKxHlBPYA==} + '@tiptap/extension-bubble-menu@2.10.4': + resolution: {integrity: sha512-GVtZwJaQyLBptMsmDtYl5GEobd1Uu7C9sc9Z+PdXwMuxmFfg+j07bCKCj5JJj/tjgXCSLVxWdTlDHxNrgzQHjw==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-bullet-list@2.10.3': - resolution: {integrity: sha512-PTkwJOVlHi4RR4Wrs044tKMceweXwNmWA6EoQ93hPUVtQcwQL990Es5Izp+i88twTPLuGD9dH+o9QDyH9SkWdA==} + '@tiptap/extension-bullet-list@2.10.4': + resolution: {integrity: sha512-JVwDPgOBYRU2ivaadOh4IaQYXQEiSw6sB36KT/bwqJF2GnEvLiMwptdRMn9Uuh6xYR3imjIZtV6uZAoneZdd6g==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-character-count@2.10.3': - resolution: {integrity: sha512-7L3VS9+SZqwK94/Yk4c+NEpI6kDUAYW3tYGuxCRiKHDlUy3fkXkVkPlxsoNUpAA4O05KGAwD0YW5rvAkNXdi8w==} + '@tiptap/extension-character-count@2.10.4': + resolution: {integrity: sha512-NoVLQI/zTEdA0EZe5+oinQ+F/WQMblZRdEWgfsUtQoLRloSAF+pFeQwDenpejdOuWqixT4vdzpboBocj4uQLsw==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-code-block@2.10.3': - resolution: {integrity: sha512-yiDVNg22fYkzsFk5kBlDSHcjwVJgajvO/M5fDXA+Hfxwo2oNcG6aJyyHXFe+UaXTVjdkPej0J6kcMKrTMCiFug==} + '@tiptap/extension-code-block@2.10.4': + resolution: {integrity: sha512-qS4jnbJqghNMT2+B+GQ807ATgqkL9OQ//NlL+ZwVSe+DPDduNA9B6IB9SrWENDfOnzekpi7kcEcm+RenELARRQ==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-code@2.10.3': - resolution: {integrity: sha512-JyLbfyY3cPctq9sVdpcRWTcoUOoq3/MnGE1eP6eBNyMTHyBPcM9TPhOkgj+xkD1zW/884jfelB+wa70RT/AMxQ==} + '@tiptap/extension-code@2.10.4': + resolution: {integrity: sha512-Vj/N0nbSQiV1o7X7pRySK9Fu72Dd266gm27TSlsts6IwJu5MklFvz7ezJUWoLjt2wmCV8/U/USmk/39ic9qjvg==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-document@2.10.3': - resolution: {integrity: sha512-6i8+xbS2zB6t8iFzli1O/QB01MmwyI5Hqiiv4m5lOxqavmJwLss2sRhoMC2hB3CyFg5UmeODy/f/RnI6q5Vixg==} + '@tiptap/extension-document@2.10.4': + resolution: {integrity: sha512-1Pqrl6Rr9bVEHJ3zO2dM7UUA0Qn/r70JQ9YLlestjW1sbMaMuY3Ifvu2uSyUE7SAGV3gvxwNVQCrv8f0VlVEaA==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-dropcursor@2.10.3': - resolution: {integrity: sha512-wzWf82ixWzZQr0hxcf/A0ul8NNxgy1N63O+c56st6OomoLuKUJWOXF+cs9O7V+/5rZKWdbdYYoRB5QLvnDBAlQ==} + '@tiptap/extension-dropcursor@2.10.4': + resolution: {integrity: sha512-0XEM/yNLaMc/sZlYOau7XpHyYiHT9LwXUe7kmze/L8eowIa/iLvmRbcnUd3rtlZ7x7wooE6UO9c7OtlREg4ZBw==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-floating-menu@2.10.3': - resolution: {integrity: sha512-Prg8rYLxeyzHxfzVu1mDkkUWMnD9ZN3y370O/1qy55e+XKVw9jFkTSuz0y0+OhMJG6bulYpDUMtb+N3+2xOWlQ==} + '@tiptap/extension-floating-menu@2.10.4': + resolution: {integrity: sha512-K2MDiu6CwQ7+Jr6g1Lh3Tuxm1L6SefSHMpQO0UW3aRGwgEV5pjlrztnBFX4K9b7MNuQ4dJGCUK9u8Cv7Xss0qg==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-gapcursor@2.10.3': - resolution: {integrity: sha512-FskZi2DqDSTH1WkgLF2OLy0xU7qj3AgHsKhVsryeAtld4jAK5EsonneWgaipbz0e/MxuIvc1oyacfZKABpLaNg==} + '@tiptap/extension-gapcursor@2.10.4': + resolution: {integrity: sha512-KbJfoaqTZePpkWAN+klpK5j0UVtELxN7H5B0J556/UCB/rnq+OsdEFHPks2Ss9TidqWzRUqcxUE50UZ7b8h7Ug==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-hard-break@2.10.3': - resolution: {integrity: sha512-2rFlimUKAgKDwT6nqAMtPBjkrknQY8S7oBNyIcDOUGyFkvbDUl3Jd0PiC929S5F3XStJRppnMqhpNDAlWmvBLA==} + '@tiptap/extension-hard-break@2.10.4': + resolution: {integrity: sha512-nW9wubW1A/CO2Ssn9wNMP08tR9Oarg9VUGzJ5qNuz38DDNyntE1SyDS+XStkeMq5nKqJ3YKhukyAJH/PiRq4Mg==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-heading@2.10.3': - resolution: {integrity: sha512-AlxXXPCWIvw8hQUDFRskasj32iMNB8Sb19VgyFWqwvntGs2/UffNu8VdsVqxD2HpZ0g5rLYCYtSW4wigs9R3og==} + '@tiptap/extension-heading@2.10.4': + resolution: {integrity: sha512-7D0h0MIvE97Gx3Qwuo2xnPDK07WfCnyh4tpOPBOus4e1g6sgxVkwDwhbkYWiwvIrf4BUVJflnke/DEDCVp6/Eg==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-history@2.10.3': - resolution: {integrity: sha512-HaSiMdx9Im9Pb9qGlVud7W8bweRDRMez33Uzs5a2x0n1RWkelfH7TwYs41Y3wus8Ujs7kw6qh7jyhvPpQBKaSA==} + '@tiptap/extension-history@2.10.4': + resolution: {integrity: sha512-fg6BNxbpMMtgKaiNI/GLcCzkxIQMwSYBhO9LA0CxLvmsWGU+My4r9W3DK6HwNoRJ9+6OleDPSLo1P73fbSTtEA==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-horizontal-rule@2.10.3': - resolution: {integrity: sha512-1a2IWhD00tgUNg/91RLnBvfENL7DLCui5L245+smcaLu+OXOOEpoBHawx59/M4hEpsjqvRRM79TzO9YXfopsPw==} + '@tiptap/extension-horizontal-rule@2.10.4': + resolution: {integrity: sha512-s9ycm/BOGoW3L0Epnj541vdngHbFbMM488HoODd1CmVSw1C+wBWFgsukgqKjlyE3VGfZXuSb1ur9zinW0RiLJQ==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-italic@2.10.3': - resolution: {integrity: sha512-wAiO6ZxoHx2H90phnKttLWGPjPZXrfKxhOCsqYrK8BpRByhr48godOFRuGwYnKaiwoVjpxc63t+kDJDWvqmgMw==} + '@tiptap/extension-italic@2.10.4': + resolution: {integrity: sha512-8MIQ+wsbyxNCZDCFTVTOXrS2AvFyOhtlBNgVU2+6r6xnJV4AcfEA3qclysqrjOlL117ped/nzDeoB0AeX0CI+Q==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-link@2.10.3': - resolution: {integrity: sha512-8esKlkZBzEiNcpt7I8Cd6l1mWmCc/66pPbUq9LfnIniDXE3U+ahBf4m3TJltYFBGbiiTR/xqMtJyVHOpuLDtAw==} + '@tiptap/extension-link@2.10.4': + resolution: {integrity: sha512-9lbtMUPc9IYCRMKV/B4k/no9J5OQQl/jJn9W2ce3NjJZSrOjuZs0CjJZgCESIaj6911s7nEJUvxKKmsbD3UC3Q==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-list-item@2.10.3': - resolution: {integrity: sha512-9sok81gvZfSta2K1Dwrq5/HSz1jk4zHBpFqCx0oydzodGslx6X1bNxdca+eXJpXZmQIWALK7zEr4X8kg3WZsgw==} + '@tiptap/extension-list-item@2.10.4': + resolution: {integrity: sha512-8K3WUD5fPyw2poQKnJGGm7zlfeIbpld92+SRF4M9wkp95EzvgexTlodvxlrL3i8zKXcQQVyExWA8kCcGPFb9bA==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-ordered-list@2.10.3': - resolution: {integrity: sha512-/SFuEDnbJxy3jvi72LeyiPHWkV+uFc0LUHTUHSh20vwyy+tLrzncJfXohGbTIv5YxYhzExQYZDRD4VbSghKdlw==} + '@tiptap/extension-ordered-list@2.10.4': + resolution: {integrity: sha512-NaeEu+qFG2O0emc8WlwOM7DKNKOaqHWuNkuKrrmQzslgL+UQSEGlGMo6NEJ5sLLckPBDpIa0MuRm30407JE+cg==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-paragraph@2.10.3': - resolution: {integrity: sha512-sNkTX/iN+YoleDiTJsrWSBw9D7c4vsYwnW5y/G5ydfuJMIRQMF78pWSIWZFDRNOMkgK5UHkhu9anrbCFYgBfaA==} + '@tiptap/extension-paragraph@2.10.4': + resolution: {integrity: sha512-SRNVhT8OXqjpZtcyuOtofbtOpXXFrQrjqqCc/yXebda//2SfUTOvB16Lss77vQOWi6xr7TF1mZuowJgSTkcczw==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-strike@2.10.3': - resolution: {integrity: sha512-jYoPy6F6njYp3txF3u23bgdRy/S5ATcWDO9LPZLHSeikwQfJ47nqb+EUNo5M8jIOgFBTn4MEbhuZ6OGyhnxopA==} + '@tiptap/extension-strike@2.10.4': + resolution: {integrity: sha512-OibipsomFpOJWTPVX/z4Z53HgwDA93lE/loHGa+ONJfML1dO6Zd6UTwzaVO1/g8WOwRgwkYu/6JnhxLKRlP8Lg==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-text-style@2.10.3': - resolution: {integrity: sha512-TalYIdlF7vBA4afFhmido7AORdBbu3sV+HCByda0FiNbM6cjng3Nr9oxHOCVJy+ChqrcgF4m54zDfLmamdyu5Q==} + '@tiptap/extension-text-style@2.10.4': + resolution: {integrity: sha512-ibq7avkcwHyUSG53Hf+P31rrwsKVbbiqbWZM4kXC7M2X3iUwFrtvaa+SWzyWQfE1jl2cCrD1+rfSkj/alcOKGg==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-text@2.10.3': - resolution: {integrity: sha512-7p9XiRprsRZm8y9jvF/sS929FCELJ5N9FQnbzikOiyGNUx5mdI+exVZlfvBr9xOD5s7fBLg6jj9Vs0fXPNRkPg==} + '@tiptap/extension-text@2.10.4': + resolution: {integrity: sha512-wPdVxCHrIS9S+8n08lgyyqRZPj9FBbyLlFt74/lV5yBC3LOorq1VKdjrTskmaj4jud7ImXoKDyBddAYTHdJ1xw==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/pm@2.10.3': - resolution: {integrity: sha512-771p53aU0KFvujvKpngvq2uAxThlEsjYaXcVVmwrhf0vxSSg+psKQEvqvWvHv/3BwkPVCGwmEKNVJZjaXFKu4g==} + '@tiptap/pm@2.10.4': + resolution: {integrity: sha512-pZ4NEkRtYoDLe0spARvXZ1N3hNv/5u6vfPdPtEbmNpoOSjSNqDC1kVM+qJY0iaCYpxbxcv7cxn3kBumcFLQpJQ==} - '@tiptap/react@2.10.3': - resolution: {integrity: sha512-5GBL3arWai8WZuCl1MMA7bT5aWwqDi5AOQhX+hovKjwHvttpKDogRoUBL5k6Eds/eQMBMGTpsfmZlGNiFxSv1g==} + '@tiptap/react@2.10.4': + resolution: {integrity: sha512-JTeqDB+xgjo46QC9ILRXe2TcSfxKVRwhZ3vDvYoemN7giRk5a/WsCF1VQIT1fax+tCl6kfv3U1f4Mkx0DkbPkA==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 - '@tiptap/starter-kit@2.10.3': - resolution: {integrity: sha512-oq8xdVIMqohSs91ofHSr7i5dCp2F56Lb9aYIAI25lZmwNwQJL2geGOYjMSfL0IC4cQHPylIuSKYCg7vRFdZmAA==} + '@tiptap/starter-kit@2.10.4': + resolution: {integrity: sha512-tu/WCs9Mkr5Nt8c3/uC4VvAbQlVX0OY7ygcqdzHGUeG9zP3twdW7o5xM3kyDKR2++sbVzqu5Ll5qNU+1JZvPGQ==} '@tootallnate/once@2.0.0': resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} @@ -4057,10 +4044,22 @@ packages: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} + call-bind-apply-helpers@1.0.1: + resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==} + engines: {node: '>= 0.4'} + call-bind@1.0.7: resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} engines: {node: '>= 0.4'} + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.3: + resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==} + engines: {node: '>= 0.4'} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -4567,6 +4566,10 @@ packages: resolution: {integrity: sha512-20TuZZHCEZ2O71q9/+8BwKwZ0QtD9D8ObhrihJPr+vLLYlSuAU3/zL4cSlgbfeoGHTjCSJBa7NGcrF9/Bx/WJQ==} engines: {node: '>=4'} + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} @@ -4623,6 +4626,10 @@ packages: resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} engines: {node: '>= 0.4'} + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + es-errors@1.3.0: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} @@ -4981,8 +4988,8 @@ packages: fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} - framer-motion@11.14.1: - resolution: {integrity: sha512-6B7jC54zgnefmUSa2l4gkc/2CrqclHL9AUbDxxRfbFyWKLd+4guUYtEabzoYMU8G5ICZ6CdJdydOLy74Ekd7ag==} + framer-motion@11.15.0: + resolution: {integrity: sha512-MLk8IvZntxOMg7lDBLw2qgTHHv664bYoYmnFTmE0Gm/FW67aOJk0WM3ctMcG+Xhcv+vh5uyyXwxvxhSeJzSe+w==} peerDependencies: '@emotion/is-prop-valid': '*' react: ^18.0.0 || ^19.0.0 @@ -5034,6 +5041,10 @@ packages: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} engines: {node: '>= 0.4'} + get-intrinsic@1.2.6: + resolution: {integrity: sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==} + engines: {node: '>= 0.4'} + get-nonce@1.0.1: resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} engines: {node: '>=6'} @@ -5100,6 +5111,10 @@ packages: gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -5133,8 +5148,8 @@ packages: peerDependencies: graphql: '>=0.11 <=16' - graphql@16.9.0: - resolution: {integrity: sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==} + graphql@16.10.0: + resolution: {integrity: sha512-AjqGKbDGUFRKIRCP9tCKiIGHyriz2oHEbPIbEtcSLSs4YjReZOIPQQWek4+6hjw62H9QShXHyaGivGiYVLeYFQ==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} has-bigints@1.0.2: @@ -5155,6 +5170,10 @@ packages: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + has-tostringtag@1.0.2: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} @@ -5707,8 +5726,8 @@ packages: json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - json-stable-stringify@1.1.1: - resolution: {integrity: sha512-SU/971Kt5qVQfJpyDveVhQ/vya+5hvrjClFOcr8c0Fq5aODJjMwutrOfCU+eCnVD5gpx1Q3fEqkyom77zH1iIg==} + json-stable-stringify@1.2.0: + resolution: {integrity: sha512-ex8jk9BZHBolvbd5cRnAgwyaYcYB0qZldy1e+LCOdcF6+AUmVZ6LcGUMzsRTW83QMeu+GxZGrcLqxqrgfXGvIw==} engines: {node: '>= 0.4'} json-to-pretty-yaml@1.2.2: @@ -5939,6 +5958,10 @@ packages: resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} hasBin: true + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + mathml-tag-names@2.1.3: resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==} @@ -6012,11 +6035,11 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} - motion-dom@11.14.1: - resolution: {integrity: sha512-Y68tHWR0d2HxHDskNxpeY3pzUdz7L/m5A8TV7VSE6Sq4XUNJdZV8zXco1aeAQ44o48u0i8UKjt8TGIqkZSQ8ew==} + motion-dom@11.14.3: + resolution: {integrity: sha512-lW+D2wBy5vxLJi6aCP0xyxTxlTfiu+b+zcpVbGVFUxotwThqhdpPRSmX8xztAgtZMPMeU0WGVn/k1w4I+TbPqA==} - motion-utils@11.14.1: - resolution: {integrity: sha512-R6SsehArpkEBUHydkcwQ/8ij8k2PyKWAJ7Y8PN3ztnFwq5RBU3zIamYH6esTp09OgsbwB57mBEZ9DORaN1WTxQ==} + motion-utils@11.14.3: + resolution: {integrity: sha512-Xg+8xnqIJTpr0L/cidfTTBFkvRw26ZtGGuIhA94J9PQ2p4mEa06Xx7QVYZH0BP+EpMSaDlu+q0I0mmvwADPsaQ==} ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} @@ -6582,8 +6605,8 @@ packages: peerDependencies: react: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 - react-csv-downloader@3.1.1: - resolution: {integrity: sha512-bQiTP8Ef3bVlFlbSVNbhtHfiSS1EmUlovU4uqvGqMaEgZ69ycZIL3nRzIcHjosUhFHcq0cTp1EH5FQrdK6UR8Q==} + react-csv-downloader@3.2.0: + resolution: {integrity: sha512-63vl4zWCht70dHEbuTkO7gdb1Xk9zZwIClLBPv1+o9Gf3rkjX4vT5B5yikBQtGnLId+wP1wY+yleaNQUvuBWGw==} engines: {npm: '>=7.0.0'} peerDependencies: react: ^16.6.3 || ^17.0.0 || ^18.0.0 @@ -6605,11 +6628,11 @@ packages: react-fast-compare@3.2.2: resolution: {integrity: sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==} - react-focus-lock@2.13.2: - resolution: {integrity: sha512-T/7bsofxYqnod2xadvuwjGKHOoL5GH7/EIPI5UyEvaU/c2CcphvGI371opFtuY/SYdbMsNiuF4HsHQ50nA/TKQ==} + react-focus-lock@2.13.5: + resolution: {integrity: sha512-HjHuZFFk2+j6ZT3LDQpyqffue541HrxUG/OFchCEwis9nstgNg0rREVRAxHBcB1lHJ5Fsxtx1qya/5xFwxDb4g==} peerDependencies: - '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -6619,8 +6642,8 @@ packages: peerDependencies: react: ^16.6.0 || ^17.0.0 || ^18.0.0 - react-hook-form@7.54.0: - resolution: {integrity: sha512-PS05+UQy/IdSbJNojBypxAo9wllhHgGmyr8/dyGQcPoiMf3e7Dfb9PWYVRco55bLbxH9S+1yDDJeTdlYCSxO3A==} + react-hook-form@7.54.1: + resolution: {integrity: sha512-PUNzFwQeQ5oHiiTUO7GO/EJXGEtuun2Y1A59rLnZBBj+vNEOWt/3ERTiG1/zt7dVeJEM+4vDX/7XQ/qanuvPMg==} engines: {node: '>=18.0.0'} peerDependencies: react: ^16.8.0 || ^17 || ^18 || ^19 @@ -6650,22 +6673,22 @@ packages: resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} - react-remove-scroll-bar@2.3.6: - resolution: {integrity: sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==} + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} engines: {node: '>=10'} peerDependencies: - '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@types/react': optional: true - react-remove-scroll@2.6.0: - resolution: {integrity: sha512-I2U4JVEsQenxDAKaVa3VZ/JeJZe0/2DxPWL8Tj8yLKctQJQiZM52pn/GWFpSp8dftjM3pSAHVJZscAnC/y+ySQ==} + react-remove-scroll@2.6.2: + resolution: {integrity: sha512-KmONPx5fnlXYJQqC62Q+lwIeAk64ws/cUw6omIumRzMRPqgnYqhSSti99nbj0Ry13bv7dF+BKn7NB+OqkdZGTw==} engines: {node: '>=10'} peerDependencies: - '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -6680,12 +6703,12 @@ packages: react-dom: optional: true - react-style-singleton@2.2.1: - resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} engines: {node: '>=10'} peerDependencies: - '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -7420,6 +7443,16 @@ packages: '@types/react': optional: true + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + use-sidecar@1.1.2: resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==} engines: {node: '>=10'} @@ -7466,8 +7499,8 @@ packages: peerDependencies: vite: '>=2.0.0' - vite@6.0.3: - resolution: {integrity: sha512-Cmuo5P0ENTN6HxLSo6IHsjCLn/81Vgrp81oaiFFMRa8gGDj5xEjIcEpf2ZymZtZR8oU0P2JX5WuUp/rlXcHkAw==} + vite@6.0.4: + resolution: {integrity: sha512-zwlH6ar+6o6b4Wp+ydhtIKLrGM/LoqZzcdVmkGAFun0KHTzIzjh+h0kungEx7KJg/PYnC80I4TII9WkjciSR6Q==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: @@ -7672,9 +7705,9 @@ packages: snapshots: - '@0no-co/graphql.web@1.0.7(graphql@16.9.0)': + '@0no-co/graphql.web@1.0.7(graphql@16.10.0)': optionalDependencies: - graphql: 16.9.0 + graphql: 16.10.0 '@adobe/css-tools@4.4.0': {} @@ -7683,7 +7716,7 @@ snapshots: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - '@ardatan/relay-compiler@12.0.0(graphql@16.9.0)': + '@ardatan/relay-compiler@12.0.0(graphql@16.10.0)': dependencies: '@babel/core': 7.26.0 '@babel/generator': 7.26.2 @@ -7696,7 +7729,7 @@ snapshots: fb-watchman: 2.0.2 fbjs: 3.0.5 glob: 7.2.3 - graphql: 16.9.0 + graphql: 16.10.0 immutable: 3.7.6 invariant: 2.2.4 nullthrows: 1.1.1 @@ -8123,10 +8156,6 @@ snapshots: dependencies: regenerator-runtime: 0.14.1 - '@babel/runtime@7.25.4': - dependencies: - regenerator-runtime: 0.14.1 - '@babel/runtime@7.26.0': dependencies: regenerator-runtime: 0.14.1 @@ -8423,43 +8452,43 @@ snapshots: '@types/json-stable-stringify': 1.0.36 '@types/node': 22.10.2 chalk: 4.1.2 - json-stable-stringify: 1.1.1 + json-stable-stringify: 1.2.0 tslib: 2.8.0 typescript: 5.7.2 optionalDependencies: ts-jest: 29.2.3(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(esbuild@0.24.0)(jest@29.7.0(@types/node@22.10.2))(typescript@5.7.2) - '@graphql-codegen/add@5.0.3(graphql@16.9.0)': + '@graphql-codegen/add@5.0.3(graphql@16.10.0)': dependencies: - '@graphql-codegen/plugin-helpers': 5.1.0(graphql@16.9.0) - graphql: 16.9.0 + '@graphql-codegen/plugin-helpers': 5.1.0(graphql@16.10.0) + graphql: 16.10.0 tslib: 2.6.3 - '@graphql-codegen/cli@5.0.3(@parcel/watcher@2.5.0)(@types/node@22.10.2)(graphql@16.9.0)(typescript@5.7.2)': + '@graphql-codegen/cli@5.0.3(@parcel/watcher@2.5.0)(@types/node@22.10.2)(graphql@16.10.0)(typescript@5.7.2)': dependencies: '@babel/generator': 7.25.7 '@babel/template': 7.25.7 '@babel/types': 7.25.7 - '@graphql-codegen/client-preset': 4.5.1(graphql@16.9.0) - '@graphql-codegen/core': 4.0.2(graphql@16.9.0) - '@graphql-codegen/plugin-helpers': 5.1.0(graphql@16.9.0) - '@graphql-tools/apollo-engine-loader': 8.0.1(graphql@16.9.0) - '@graphql-tools/code-file-loader': 8.1.2(graphql@16.9.0) - '@graphql-tools/git-loader': 8.0.6(graphql@16.9.0) - '@graphql-tools/github-loader': 8.0.1(@types/node@22.10.2)(graphql@16.9.0) - '@graphql-tools/graphql-file-loader': 8.0.1(graphql@16.9.0) - '@graphql-tools/json-file-loader': 8.0.1(graphql@16.9.0) - '@graphql-tools/load': 8.0.2(graphql@16.9.0) - '@graphql-tools/prisma-loader': 8.0.4(@types/node@22.10.2)(graphql@16.9.0) - '@graphql-tools/url-loader': 8.0.2(@types/node@22.10.2)(graphql@16.9.0) - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) + '@graphql-codegen/client-preset': 4.5.1(graphql@16.10.0) + '@graphql-codegen/core': 4.0.2(graphql@16.10.0) + '@graphql-codegen/plugin-helpers': 5.1.0(graphql@16.10.0) + '@graphql-tools/apollo-engine-loader': 8.0.1(graphql@16.10.0) + '@graphql-tools/code-file-loader': 8.1.2(graphql@16.10.0) + '@graphql-tools/git-loader': 8.0.6(graphql@16.10.0) + '@graphql-tools/github-loader': 8.0.1(@types/node@22.10.2)(graphql@16.10.0) + '@graphql-tools/graphql-file-loader': 8.0.1(graphql@16.10.0) + '@graphql-tools/json-file-loader': 8.0.1(graphql@16.10.0) + '@graphql-tools/load': 8.0.2(graphql@16.10.0) + '@graphql-tools/prisma-loader': 8.0.4(@types/node@22.10.2)(graphql@16.10.0) + '@graphql-tools/url-loader': 8.0.2(@types/node@22.10.2)(graphql@16.10.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) '@whatwg-node/fetch': 0.9.22 chalk: 4.1.2 cosmiconfig: 8.3.6(typescript@5.7.2) debounce: 1.2.1 detect-indent: 6.1.0 - graphql: 16.9.0 - graphql-config: 5.1.3(@types/node@22.10.2)(graphql@16.9.0)(typescript@5.7.2) + graphql: 16.10.0 + graphql-config: 5.1.3(@types/node@22.10.2)(graphql@16.10.0)(typescript@5.7.2) inquirer: 8.2.6 is-glob: 4.0.3 jiti: 1.21.6 @@ -8485,167 +8514,167 @@ snapshots: - typescript - utf-8-validate - '@graphql-codegen/client-preset@4.5.1(graphql@16.9.0)': + '@graphql-codegen/client-preset@4.5.1(graphql@16.10.0)': dependencies: '@babel/helper-plugin-utils': 7.24.7 '@babel/template': 7.25.7 - '@graphql-codegen/add': 5.0.3(graphql@16.9.0) - '@graphql-codegen/gql-tag-operations': 4.0.12(graphql@16.9.0) - '@graphql-codegen/plugin-helpers': 5.1.0(graphql@16.9.0) - '@graphql-codegen/typed-document-node': 5.0.12(graphql@16.9.0) - '@graphql-codegen/typescript': 4.1.2(graphql@16.9.0) - '@graphql-codegen/typescript-operations': 4.4.0(graphql@16.9.0) - '@graphql-codegen/visitor-plugin-common': 5.6.0(graphql@16.9.0) - '@graphql-tools/documents': 1.0.1(graphql@16.9.0) - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) - '@graphql-typed-document-node/core': 3.2.0(graphql@16.9.0) - graphql: 16.9.0 + '@graphql-codegen/add': 5.0.3(graphql@16.10.0) + '@graphql-codegen/gql-tag-operations': 4.0.12(graphql@16.10.0) + '@graphql-codegen/plugin-helpers': 5.1.0(graphql@16.10.0) + '@graphql-codegen/typed-document-node': 5.0.12(graphql@16.10.0) + '@graphql-codegen/typescript': 4.1.2(graphql@16.10.0) + '@graphql-codegen/typescript-operations': 4.4.0(graphql@16.10.0) + '@graphql-codegen/visitor-plugin-common': 5.6.0(graphql@16.10.0) + '@graphql-tools/documents': 1.0.1(graphql@16.10.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) + '@graphql-typed-document-node/core': 3.2.0(graphql@16.10.0) + graphql: 16.10.0 tslib: 2.6.3 transitivePeerDependencies: - encoding - supports-color - '@graphql-codegen/core@4.0.2(graphql@16.9.0)': + '@graphql-codegen/core@4.0.2(graphql@16.10.0)': dependencies: - '@graphql-codegen/plugin-helpers': 5.1.0(graphql@16.9.0) - '@graphql-tools/schema': 10.0.4(graphql@16.9.0) - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) - graphql: 16.9.0 + '@graphql-codegen/plugin-helpers': 5.1.0(graphql@16.10.0) + '@graphql-tools/schema': 10.0.4(graphql@16.10.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) + graphql: 16.10.0 tslib: 2.6.3 - '@graphql-codegen/gql-tag-operations@4.0.12(graphql@16.9.0)': + '@graphql-codegen/gql-tag-operations@4.0.12(graphql@16.10.0)': dependencies: - '@graphql-codegen/plugin-helpers': 5.1.0(graphql@16.9.0) - '@graphql-codegen/visitor-plugin-common': 5.6.0(graphql@16.9.0) - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) + '@graphql-codegen/plugin-helpers': 5.1.0(graphql@16.10.0) + '@graphql-codegen/visitor-plugin-common': 5.6.0(graphql@16.10.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) auto-bind: 4.0.0 - graphql: 16.9.0 + graphql: 16.10.0 tslib: 2.6.3 transitivePeerDependencies: - encoding - supports-color - '@graphql-codegen/plugin-helpers@5.1.0(graphql@16.9.0)': + '@graphql-codegen/plugin-helpers@5.1.0(graphql@16.10.0)': dependencies: - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) change-case-all: 1.0.15 common-tags: 1.8.2 - graphql: 16.9.0 + graphql: 16.10.0 import-from: 4.0.0 lodash: 4.17.21 tslib: 2.6.3 - '@graphql-codegen/schema-ast@4.1.0(graphql@16.9.0)': + '@graphql-codegen/schema-ast@4.1.0(graphql@16.10.0)': dependencies: - '@graphql-codegen/plugin-helpers': 5.1.0(graphql@16.9.0) - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) - graphql: 16.9.0 + '@graphql-codegen/plugin-helpers': 5.1.0(graphql@16.10.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) + graphql: 16.10.0 tslib: 2.6.3 - '@graphql-codegen/typed-document-node@5.0.12(graphql@16.9.0)': + '@graphql-codegen/typed-document-node@5.0.12(graphql@16.10.0)': dependencies: - '@graphql-codegen/plugin-helpers': 5.1.0(graphql@16.9.0) - '@graphql-codegen/visitor-plugin-common': 5.6.0(graphql@16.9.0) + '@graphql-codegen/plugin-helpers': 5.1.0(graphql@16.10.0) + '@graphql-codegen/visitor-plugin-common': 5.6.0(graphql@16.10.0) auto-bind: 4.0.0 change-case-all: 1.0.15 - graphql: 16.9.0 + graphql: 16.10.0 tslib: 2.6.3 transitivePeerDependencies: - encoding - supports-color - '@graphql-codegen/typescript-operations@4.4.0(graphql@16.9.0)': + '@graphql-codegen/typescript-operations@4.4.0(graphql@16.10.0)': dependencies: - '@graphql-codegen/plugin-helpers': 5.1.0(graphql@16.9.0) - '@graphql-codegen/typescript': 4.1.2(graphql@16.9.0) - '@graphql-codegen/visitor-plugin-common': 5.6.0(graphql@16.9.0) + '@graphql-codegen/plugin-helpers': 5.1.0(graphql@16.10.0) + '@graphql-codegen/typescript': 4.1.2(graphql@16.10.0) + '@graphql-codegen/visitor-plugin-common': 5.6.0(graphql@16.10.0) auto-bind: 4.0.0 - graphql: 16.9.0 + graphql: 16.10.0 tslib: 2.6.3 transitivePeerDependencies: - encoding - supports-color - '@graphql-codegen/typescript@4.1.2(graphql@16.9.0)': + '@graphql-codegen/typescript@4.1.2(graphql@16.10.0)': dependencies: - '@graphql-codegen/plugin-helpers': 5.1.0(graphql@16.9.0) - '@graphql-codegen/schema-ast': 4.1.0(graphql@16.9.0) - '@graphql-codegen/visitor-plugin-common': 5.6.0(graphql@16.9.0) + '@graphql-codegen/plugin-helpers': 5.1.0(graphql@16.10.0) + '@graphql-codegen/schema-ast': 4.1.0(graphql@16.10.0) + '@graphql-codegen/visitor-plugin-common': 5.6.0(graphql@16.10.0) auto-bind: 4.0.0 - graphql: 16.9.0 + graphql: 16.10.0 tslib: 2.6.3 transitivePeerDependencies: - encoding - supports-color - '@graphql-codegen/visitor-plugin-common@5.6.0(graphql@16.9.0)': + '@graphql-codegen/visitor-plugin-common@5.6.0(graphql@16.10.0)': dependencies: - '@graphql-codegen/plugin-helpers': 5.1.0(graphql@16.9.0) - '@graphql-tools/optimize': 2.0.0(graphql@16.9.0) - '@graphql-tools/relay-operation-optimizer': 7.0.1(graphql@16.9.0) - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) + '@graphql-codegen/plugin-helpers': 5.1.0(graphql@16.10.0) + '@graphql-tools/optimize': 2.0.0(graphql@16.10.0) + '@graphql-tools/relay-operation-optimizer': 7.0.1(graphql@16.10.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) auto-bind: 4.0.0 change-case-all: 1.0.15 dependency-graph: 0.11.0 - graphql: 16.9.0 - graphql-tag: 2.12.6(graphql@16.9.0) + graphql: 16.10.0 + graphql-tag: 2.12.6(graphql@16.10.0) parse-filepath: 1.0.2 tslib: 2.6.3 transitivePeerDependencies: - encoding - supports-color - '@graphql-tools/apollo-engine-loader@8.0.1(graphql@16.9.0)': + '@graphql-tools/apollo-engine-loader@8.0.1(graphql@16.10.0)': dependencies: '@ardatan/sync-fetch': 0.0.1 - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) '@whatwg-node/fetch': 0.9.22 - graphql: 16.9.0 + graphql: 16.10.0 tslib: 2.8.0 transitivePeerDependencies: - encoding - '@graphql-tools/batch-execute@9.0.4(graphql@16.9.0)': + '@graphql-tools/batch-execute@9.0.4(graphql@16.10.0)': dependencies: - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) dataloader: 2.2.3 - graphql: 16.9.0 + graphql: 16.10.0 tslib: 2.8.0 value-or-promise: 1.0.12 - '@graphql-tools/code-file-loader@8.1.2(graphql@16.9.0)': + '@graphql-tools/code-file-loader@8.1.2(graphql@16.10.0)': dependencies: - '@graphql-tools/graphql-tag-pluck': 8.3.1(graphql@16.9.0) - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) + '@graphql-tools/graphql-tag-pluck': 8.3.1(graphql@16.10.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) globby: 11.1.0 - graphql: 16.9.0 + graphql: 16.10.0 tslib: 2.8.0 unixify: 1.0.0 transitivePeerDependencies: - supports-color - '@graphql-tools/delegate@10.0.13(graphql@16.9.0)': + '@graphql-tools/delegate@10.0.13(graphql@16.10.0)': dependencies: - '@graphql-tools/batch-execute': 9.0.4(graphql@16.9.0) - '@graphql-tools/executor': 1.2.8(graphql@16.9.0) - '@graphql-tools/schema': 10.0.4(graphql@16.9.0) - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) + '@graphql-tools/batch-execute': 9.0.4(graphql@16.10.0) + '@graphql-tools/executor': 1.2.8(graphql@16.10.0) + '@graphql-tools/schema': 10.0.4(graphql@16.10.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) dataloader: 2.2.3 - graphql: 16.9.0 + graphql: 16.10.0 tslib: 2.8.0 - '@graphql-tools/documents@1.0.1(graphql@16.9.0)': + '@graphql-tools/documents@1.0.1(graphql@16.10.0)': dependencies: - graphql: 16.9.0 + graphql: 16.10.0 lodash.sortby: 4.7.0 tslib: 2.8.0 - '@graphql-tools/executor-graphql-ws@1.1.2(graphql@16.9.0)': + '@graphql-tools/executor-graphql-ws@1.1.2(graphql@16.10.0)': dependencies: - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) '@types/ws': 8.5.10 - graphql: 16.9.0 - graphql-ws: 5.16.0(graphql@16.9.0) + graphql: 16.10.0 + graphql-ws: 5.16.0(graphql@16.10.0) isomorphic-ws: 5.0.0(ws@8.18.0) tslib: 2.8.0 ws: 8.18.0 @@ -8653,24 +8682,24 @@ snapshots: - bufferutil - utf-8-validate - '@graphql-tools/executor-http@1.0.9(@types/node@22.10.2)(graphql@16.9.0)': + '@graphql-tools/executor-http@1.0.9(@types/node@22.10.2)(graphql@16.10.0)': dependencies: - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) '@repeaterjs/repeater': 3.0.6 '@whatwg-node/fetch': 0.9.22 extract-files: 11.0.0 - graphql: 16.9.0 + graphql: 16.10.0 meros: 1.3.0(@types/node@22.10.2) tslib: 2.8.0 value-or-promise: 1.0.12 transitivePeerDependencies: - '@types/node' - '@graphql-tools/executor-legacy-ws@1.0.6(graphql@16.9.0)': + '@graphql-tools/executor-legacy-ws@1.0.6(graphql@16.10.0)': dependencies: - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) '@types/ws': 8.5.10 - graphql: 16.9.0 + graphql: 16.10.0 isomorphic-ws: 5.0.0(ws@8.18.0) tslib: 2.8.0 ws: 8.18.0 @@ -8678,20 +8707,20 @@ snapshots: - bufferutil - utf-8-validate - '@graphql-tools/executor@1.2.8(graphql@16.9.0)': + '@graphql-tools/executor@1.2.8(graphql@16.10.0)': dependencies: - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) - '@graphql-typed-document-node/core': 3.2.0(graphql@16.9.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) + '@graphql-typed-document-node/core': 3.2.0(graphql@16.10.0) '@repeaterjs/repeater': 3.0.6 - graphql: 16.9.0 + graphql: 16.10.0 tslib: 2.8.0 value-or-promise: 1.0.12 - '@graphql-tools/git-loader@8.0.6(graphql@16.9.0)': + '@graphql-tools/git-loader@8.0.6(graphql@16.10.0)': dependencies: - '@graphql-tools/graphql-tag-pluck': 8.3.1(graphql@16.9.0) - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) - graphql: 16.9.0 + '@graphql-tools/graphql-tag-pluck': 8.3.1(graphql@16.10.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) + graphql: 16.10.0 is-glob: 4.0.3 micromatch: 4.0.7 tslib: 2.8.0 @@ -8699,14 +8728,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@graphql-tools/github-loader@8.0.1(@types/node@22.10.2)(graphql@16.9.0)': + '@graphql-tools/github-loader@8.0.1(@types/node@22.10.2)(graphql@16.10.0)': dependencies: '@ardatan/sync-fetch': 0.0.1 - '@graphql-tools/executor-http': 1.0.9(@types/node@22.10.2)(graphql@16.9.0) - '@graphql-tools/graphql-tag-pluck': 8.3.1(graphql@16.9.0) - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) + '@graphql-tools/executor-http': 1.0.9(@types/node@22.10.2)(graphql@16.10.0) + '@graphql-tools/graphql-tag-pluck': 8.3.1(graphql@16.10.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) '@whatwg-node/fetch': 0.9.22 - graphql: 16.9.0 + graphql: 16.10.0 tslib: 2.8.0 value-or-promise: 1.0.12 transitivePeerDependencies: @@ -8714,73 +8743,73 @@ snapshots: - encoding - supports-color - '@graphql-tools/graphql-file-loader@8.0.1(graphql@16.9.0)': + '@graphql-tools/graphql-file-loader@8.0.1(graphql@16.10.0)': dependencies: - '@graphql-tools/import': 7.0.1(graphql@16.9.0) - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) + '@graphql-tools/import': 7.0.1(graphql@16.10.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) globby: 11.1.0 - graphql: 16.9.0 + graphql: 16.10.0 tslib: 2.8.0 unixify: 1.0.0 - '@graphql-tools/graphql-tag-pluck@8.3.1(graphql@16.9.0)': + '@graphql-tools/graphql-tag-pluck@8.3.1(graphql@16.10.0)': dependencies: '@babel/core': 7.26.0 '@babel/parser': 7.26.2 '@babel/plugin-syntax-import-assertions': 7.24.7(@babel/core@7.26.0) '@babel/traverse': 7.25.9 '@babel/types': 7.26.0 - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) - graphql: 16.9.0 + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) + graphql: 16.10.0 tslib: 2.8.0 transitivePeerDependencies: - supports-color - '@graphql-tools/import@7.0.1(graphql@16.9.0)': + '@graphql-tools/import@7.0.1(graphql@16.10.0)': dependencies: - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) - graphql: 16.9.0 + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) + graphql: 16.10.0 resolve-from: 5.0.0 tslib: 2.8.0 - '@graphql-tools/json-file-loader@8.0.1(graphql@16.9.0)': + '@graphql-tools/json-file-loader@8.0.1(graphql@16.10.0)': dependencies: - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) globby: 11.1.0 - graphql: 16.9.0 + graphql: 16.10.0 tslib: 2.8.0 unixify: 1.0.0 - '@graphql-tools/load@8.0.2(graphql@16.9.0)': + '@graphql-tools/load@8.0.2(graphql@16.10.0)': dependencies: - '@graphql-tools/schema': 10.0.4(graphql@16.9.0) - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) - graphql: 16.9.0 + '@graphql-tools/schema': 10.0.4(graphql@16.10.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) + graphql: 16.10.0 p-limit: 3.1.0 tslib: 2.8.0 - '@graphql-tools/merge@9.0.4(graphql@16.9.0)': + '@graphql-tools/merge@9.0.4(graphql@16.10.0)': dependencies: - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) - graphql: 16.9.0 + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) + graphql: 16.10.0 tslib: 2.8.0 - '@graphql-tools/optimize@2.0.0(graphql@16.9.0)': + '@graphql-tools/optimize@2.0.0(graphql@16.10.0)': dependencies: - graphql: 16.9.0 + graphql: 16.10.0 tslib: 2.8.0 - '@graphql-tools/prisma-loader@8.0.4(@types/node@22.10.2)(graphql@16.9.0)': + '@graphql-tools/prisma-loader@8.0.4(@types/node@22.10.2)(graphql@16.10.0)': dependencies: - '@graphql-tools/url-loader': 8.0.2(@types/node@22.10.2)(graphql@16.9.0) - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) + '@graphql-tools/url-loader': 8.0.2(@types/node@22.10.2)(graphql@16.10.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) '@types/js-yaml': 4.0.9 '@whatwg-node/fetch': 0.9.22 chalk: 4.1.2 debug: 4.3.7 dotenv: 16.4.7 - graphql: 16.9.0 - graphql-request: 6.1.0(graphql@16.9.0) + graphql: 16.10.0 + graphql-request: 6.1.0(graphql@16.10.0) http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.5 jose: 5.6.3 @@ -8796,36 +8825,36 @@ snapshots: - supports-color - utf-8-validate - '@graphql-tools/relay-operation-optimizer@7.0.1(graphql@16.9.0)': + '@graphql-tools/relay-operation-optimizer@7.0.1(graphql@16.10.0)': dependencies: - '@ardatan/relay-compiler': 12.0.0(graphql@16.9.0) - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) - graphql: 16.9.0 + '@ardatan/relay-compiler': 12.0.0(graphql@16.10.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) + graphql: 16.10.0 tslib: 2.8.0 transitivePeerDependencies: - encoding - supports-color - '@graphql-tools/schema@10.0.4(graphql@16.9.0)': + '@graphql-tools/schema@10.0.4(graphql@16.10.0)': dependencies: - '@graphql-tools/merge': 9.0.4(graphql@16.9.0) - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) - graphql: 16.9.0 + '@graphql-tools/merge': 9.0.4(graphql@16.10.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) + graphql: 16.10.0 tslib: 2.8.0 value-or-promise: 1.0.12 - '@graphql-tools/url-loader@8.0.2(@types/node@22.10.2)(graphql@16.9.0)': + '@graphql-tools/url-loader@8.0.2(@types/node@22.10.2)(graphql@16.10.0)': dependencies: '@ardatan/sync-fetch': 0.0.1 - '@graphql-tools/delegate': 10.0.13(graphql@16.9.0) - '@graphql-tools/executor-graphql-ws': 1.1.2(graphql@16.9.0) - '@graphql-tools/executor-http': 1.0.9(@types/node@22.10.2)(graphql@16.9.0) - '@graphql-tools/executor-legacy-ws': 1.0.6(graphql@16.9.0) - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) - '@graphql-tools/wrap': 10.0.5(graphql@16.9.0) + '@graphql-tools/delegate': 10.0.13(graphql@16.10.0) + '@graphql-tools/executor-graphql-ws': 1.1.2(graphql@16.10.0) + '@graphql-tools/executor-http': 1.0.9(@types/node@22.10.2)(graphql@16.10.0) + '@graphql-tools/executor-legacy-ws': 1.0.6(graphql@16.10.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) + '@graphql-tools/wrap': 10.0.5(graphql@16.10.0) '@types/ws': 8.5.10 '@whatwg-node/fetch': 0.9.22 - graphql: 16.9.0 + graphql: 16.10.0 isomorphic-ws: 5.0.0(ws@8.18.0) tslib: 2.8.0 value-or-promise: 1.0.12 @@ -8836,36 +8865,36 @@ snapshots: - encoding - utf-8-validate - '@graphql-tools/utils@10.2.3(graphql@16.9.0)': + '@graphql-tools/utils@10.2.3(graphql@16.10.0)': dependencies: - '@graphql-typed-document-node/core': 3.2.0(graphql@16.9.0) + '@graphql-typed-document-node/core': 3.2.0(graphql@16.10.0) cross-inspect: 1.0.0 dset: 3.1.3 - graphql: 16.9.0 + graphql: 16.10.0 tslib: 2.8.0 - '@graphql-tools/wrap@10.0.5(graphql@16.9.0)': + '@graphql-tools/wrap@10.0.5(graphql@16.10.0)': dependencies: - '@graphql-tools/delegate': 10.0.13(graphql@16.9.0) - '@graphql-tools/schema': 10.0.4(graphql@16.9.0) - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) - graphql: 16.9.0 + '@graphql-tools/delegate': 10.0.13(graphql@16.10.0) + '@graphql-tools/schema': 10.0.4(graphql@16.10.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) + graphql: 16.10.0 tslib: 2.8.0 value-or-promise: 1.0.12 - '@graphql-typed-document-node/core@3.2.0(graphql@16.9.0)': + '@graphql-typed-document-node/core@3.2.0(graphql@16.10.0)': dependencies: - graphql: 16.9.0 + graphql: 16.10.0 '@heroicons/react@2.2.0(react@18.3.1)': dependencies: react: 18.3.1 - '@hookform/error-message@2.0.1(react-dom@18.3.1(react@18.3.1))(react-hook-form@7.54.0(react@18.3.1))(react@18.3.1)': + '@hookform/error-message@2.0.1(react-dom@18.3.1(react@18.3.1))(react-hook-form@7.54.1(react@18.3.1))(react@18.3.1)': dependencies: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-hook-form: 7.54.0(react@18.3.1) + react-hook-form: 7.54.1(react@18.3.1) '@humanwhocodes/config-array@0.11.14': dependencies: @@ -9083,11 +9112,11 @@ snapshots: '@types/yargs': 17.0.32 chalk: 4.1.2 - '@joshwooding/vite-plugin-react-docgen-typescript@0.4.2(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5))': + '@joshwooding/vite-plugin-react-docgen-typescript@0.4.2(typescript@5.7.2)(vite@6.0.4(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5))': dependencies: magic-string: 0.27.0 react-docgen-typescript: 2.2.2(typescript@5.7.2) - vite: 6.0.3(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5) + vite: 6.0.4(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5) optionalDependencies: typescript: 5.7.2 @@ -9315,18 +9344,18 @@ snapshots: '@radix-ui/number@1.1.0': {} - '@radix-ui/primitive@1.1.0': {} + '@radix-ui/primitive@1.1.1': {} - '@radix-ui/react-accordion@1.2.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-accordion@1.2.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-collapsible': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-collapsible': 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-collection': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-context': 1.1.1(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-direction': 1.1.0(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-id': 1.1.0(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.13)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -9334,37 +9363,37 @@ snapshots: '@types/react': 18.3.13 '@types/react-dom': 18.3.1 - '@radix-ui/react-alert-dialog@1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-alert-dialog@1.1.4(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-context': 1.1.1(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-dialog': 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.1.0(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/react-dialog': 1.1.4(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.1.1(@types/react@18.3.13)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.13 '@types/react-dom': 18.3.1 - '@radix-ui/react-arrow@1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-arrow@1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.13 '@types/react-dom': 18.3.1 - '@radix-ui/react-collapsible@1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-collapsible@1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-context': 1.1.1(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-id': 1.1.0(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-presence': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.13)(react@18.3.1) react: 18.3.1 @@ -9373,25 +9402,19 @@ snapshots: '@types/react': 18.3.13 '@types/react-dom': 18.3.1 - '@radix-ui/react-collection@1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-collection@1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-context': 1.1.0(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.1.0(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.1.1(@types/react@18.3.13)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.13 '@types/react-dom': 18.3.1 - '@radix-ui/react-compose-refs@1.1.0(@types/react@18.3.13)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.13 - - '@radix-ui/react-context@1.1.0(@types/react@18.3.13)(react@18.3.1)': + '@radix-ui/react-compose-refs@1.1.1(@types/react@18.3.13)(react@18.3.1)': dependencies: react: 18.3.1 optionalDependencies: @@ -9403,24 +9426,24 @@ snapshots: optionalDependencies: '@types/react': 18.3.13 - '@radix-ui/react-dialog@1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-dialog@1.1.4(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-context': 1.1.1(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.3(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-focus-guards': 1.1.1(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-id': 1.1.0(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-portal': 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.1.0(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/react-portal': 1.1.3(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.1.1(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.13)(react@18.3.1) aria-hidden: 1.2.4 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.6.0(@types/react@18.3.13)(react@18.3.1) + react-remove-scroll: 2.6.2(@types/react@18.3.13)(react@18.3.1) optionalDependencies: '@types/react': 18.3.13 '@types/react-dom': 18.3.1 @@ -9431,11 +9454,11 @@ snapshots: optionalDependencies: '@types/react': 18.3.13 - '@radix-ui/react-dismissable-layer@1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-dismissable-layer@1.1.3(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@18.3.13)(react@18.3.1) react: 18.3.1 @@ -9444,14 +9467,14 @@ snapshots: '@types/react': 18.3.13 '@types/react-dom': 18.3.1 - '@radix-ui/react-dropdown-menu@2.1.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-dropdown-menu@2.1.4(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-context': 1.1.1(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-id': 1.1.0(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-menu': 2.1.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-menu': 2.1.4(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.13)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -9465,10 +9488,10 @@ snapshots: optionalDependencies: '@types/react': 18.3.13 - '@radix-ui/react-focus-scope@1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-focus-scope@1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.13)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -9483,61 +9506,61 @@ snapshots: optionalDependencies: '@types/react': 18.3.13 - '@radix-ui/react-menu@2.1.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-menu@2.1.4(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-collection': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-context': 1.1.1(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-direction': 1.1.0(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.3(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-focus-guards': 1.1.1(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-id': 1.1.0(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-popper': 1.2.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.1.0(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/react-popper': 1.2.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-portal': 1.1.3(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-roving-focus': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.1.1(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.13)(react@18.3.1) aria-hidden: 1.2.4 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.6.0(@types/react@18.3.13)(react@18.3.1) + react-remove-scroll: 2.6.2(@types/react@18.3.13)(react@18.3.1) optionalDependencies: '@types/react': 18.3.13 '@types/react-dom': 18.3.1 - '@radix-ui/react-navigation-menu@1.2.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-navigation-menu@1.2.3(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-collection': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-context': 1.1.1(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-direction': 1.1.0(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.3(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-id': 1.1.0(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-presence': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-visually-hidden': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.13 '@types/react-dom': 18.3.1 - '@radix-ui/react-popper@1.2.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-popper@1.2.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@floating-ui/react-dom': 2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-arrow': 1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-context': 1.1.0(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-arrow': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-use-rect': 1.1.0(@types/react@18.3.13)(react@18.3.1) @@ -9549,9 +9572,9 @@ snapshots: '@types/react': 18.3.13 '@types/react-dom': 18.3.1 - '@radix-ui/react-portal@1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-portal@1.1.3(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.13)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -9559,9 +9582,9 @@ snapshots: '@types/react': 18.3.13 '@types/react-dom': 18.3.1 - '@radix-ui/react-presence@1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-presence@1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.13)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -9569,24 +9592,24 @@ snapshots: '@types/react': 18.3.13 '@types/react-dom': 18.3.1 - '@radix-ui/react-primitive@2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-primitive@2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-slot': 1.1.0(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/react-slot': 1.1.1(@types/react@18.3.13)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.13 '@types/react-dom': 18.3.1 - '@radix-ui/react-roving-focus@1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-roving-focus@1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-context': 1.1.0(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-collection': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-direction': 1.1.0(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-id': 1.1.0(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.13)(react@18.3.1) react: 18.3.1 @@ -9595,15 +9618,15 @@ snapshots: '@types/react': 18.3.13 '@types/react-dom': 18.3.1 - '@radix-ui/react-scroll-area@1.2.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-scroll-area@1.2.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/number': 1.1.0 - '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-context': 1.1.1(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-direction': 1.1.0(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-presence': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.13)(react@18.3.1) react: 18.3.1 @@ -9612,28 +9635,28 @@ snapshots: '@types/react': 18.3.13 '@types/react-dom': 18.3.1 - '@radix-ui/react-separator@1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-separator@1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.13 '@types/react-dom': 18.3.1 - '@radix-ui/react-slot@1.1.0(@types/react@18.3.13)(react@18.3.1)': + '@radix-ui/react-slot@1.1.1(@types/react@18.3.13)(react@18.3.1)': dependencies: - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.13)(react@18.3.1) react: 18.3.1 optionalDependencies: '@types/react': 18.3.13 - '@radix-ui/react-switch@1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-switch@1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-context': 1.1.1(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-use-size': 1.1.0(@types/react@18.3.13)(react@18.3.1) @@ -9643,15 +9666,15 @@ snapshots: '@types/react': 18.3.13 '@types/react-dom': 18.3.1 - '@radix-ui/react-tabs@1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-tabs@1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/primitive': 1.1.0 + '@radix-ui/primitive': 1.1.1 '@radix-ui/react-context': 1.1.1(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-direction': 1.1.0(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-id': 1.1.0(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-presence': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-roving-focus': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.13)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -9659,14 +9682,14 @@ snapshots: '@types/react': 18.3.13 '@types/react-dom': 18.3.1 - '@radix-ui/react-toggle-group@1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-toggle-group@1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-context': 1.1.0(@types/react@18.3.13)(react@18.3.1) + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-context': 1.1.1(@types/react@18.3.13)(react@18.3.1) '@radix-ui/react-direction': 1.1.0(@types/react@18.3.13)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-toggle': 1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-roving-focus': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-toggle': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.13)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -9674,10 +9697,10 @@ snapshots: '@types/react': 18.3.13 '@types/react-dom': 18.3.1 - '@radix-ui/react-toggle@1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-toggle@1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.13)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -9731,9 +9754,9 @@ snapshots: optionalDependencies: '@types/react': 18.3.13 - '@radix-ui/react-visually-hidden@1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-visually-hidden@1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.1)(@types/react@18.3.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: @@ -9936,13 +9959,13 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@storybook/builder-vite@8.4.7(storybook@8.4.7(prettier@3.4.2))(vite@6.0.3(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5))': + '@storybook/builder-vite@8.4.7(storybook@8.4.7(prettier@3.4.2))(vite@6.0.4(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5))': dependencies: '@storybook/csf-plugin': 8.4.7(storybook@8.4.7(prettier@3.4.2)) browser-assert: 1.2.1 storybook: 8.4.7(prettier@3.4.2) ts-dedent: 2.2.0 - vite: 6.0.3(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5) + vite: 6.0.4(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5) '@storybook/components@8.4.7(storybook@8.4.7(prettier@3.4.2))': dependencies: @@ -9998,11 +10021,11 @@ snapshots: react-dom: 18.3.1(react@18.3.1) storybook: 8.4.7(prettier@3.4.2) - '@storybook/react-vite@8.4.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.27.4)(storybook@8.4.7(prettier@3.4.2))(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5))': + '@storybook/react-vite@8.4.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.27.4)(storybook@8.4.7(prettier@3.4.2))(typescript@5.7.2)(vite@6.0.4(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5))': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.4.2(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5)) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.4.2(typescript@5.7.2)(vite@6.0.4(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5)) '@rollup/pluginutils': 5.1.0(rollup@4.27.4) - '@storybook/builder-vite': 8.4.7(storybook@8.4.7(prettier@3.4.2))(vite@6.0.3(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5)) + '@storybook/builder-vite': 8.4.7(storybook@8.4.7(prettier@3.4.2))(vite@6.0.4(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5)) '@storybook/react': 8.4.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.7(prettier@3.4.2))(typescript@5.7.2) find-up: 5.0.0 magic-string: 0.30.10 @@ -10012,7 +10035,7 @@ snapshots: resolve: 1.22.8 storybook: 8.4.7(prettier@3.4.2) tsconfig-paths: 4.2.0 - vite: 6.0.3(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5) + vite: 6.0.4(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5) transitivePeerDependencies: - '@storybook/test' - rollup @@ -10041,7 +10064,7 @@ snapshots: dependencies: storybook: 8.4.7(prettier@3.4.2) - '@tanstack/react-table@8.20.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@tanstack/react-table@8.20.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@tanstack/table-core': 8.20.5 react: 18.3.1 @@ -10084,115 +10107,115 @@ snapshots: dependencies: '@testing-library/dom': 10.1.0 - '@tiptap/core@2.10.3(@tiptap/pm@2.10.3)': + '@tiptap/core@2.10.4(@tiptap/pm@2.10.4)': dependencies: - '@tiptap/pm': 2.10.3 + '@tiptap/pm': 2.10.4 - '@tiptap/extension-blockquote@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-blockquote@2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.10.4(@tiptap/pm@2.10.4) - '@tiptap/extension-bold@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-bold@2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.10.4(@tiptap/pm@2.10.4) - '@tiptap/extension-bubble-menu@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)': + '@tiptap/extension-bubble-menu@2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))(@tiptap/pm@2.10.4)': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) - '@tiptap/pm': 2.10.3 + '@tiptap/core': 2.10.4(@tiptap/pm@2.10.4) + '@tiptap/pm': 2.10.4 tippy.js: 6.3.7 - '@tiptap/extension-bullet-list@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-bullet-list@2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.10.4(@tiptap/pm@2.10.4) - '@tiptap/extension-character-count@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)': + '@tiptap/extension-character-count@2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))(@tiptap/pm@2.10.4)': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) - '@tiptap/pm': 2.10.3 + '@tiptap/core': 2.10.4(@tiptap/pm@2.10.4) + '@tiptap/pm': 2.10.4 - '@tiptap/extension-code-block@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)': + '@tiptap/extension-code-block@2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))(@tiptap/pm@2.10.4)': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) - '@tiptap/pm': 2.10.3 + '@tiptap/core': 2.10.4(@tiptap/pm@2.10.4) + '@tiptap/pm': 2.10.4 - '@tiptap/extension-code@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-code@2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.10.4(@tiptap/pm@2.10.4) - '@tiptap/extension-document@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-document@2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.10.4(@tiptap/pm@2.10.4) - '@tiptap/extension-dropcursor@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)': + '@tiptap/extension-dropcursor@2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))(@tiptap/pm@2.10.4)': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) - '@tiptap/pm': 2.10.3 + '@tiptap/core': 2.10.4(@tiptap/pm@2.10.4) + '@tiptap/pm': 2.10.4 - '@tiptap/extension-floating-menu@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)': + '@tiptap/extension-floating-menu@2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))(@tiptap/pm@2.10.4)': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) - '@tiptap/pm': 2.10.3 + '@tiptap/core': 2.10.4(@tiptap/pm@2.10.4) + '@tiptap/pm': 2.10.4 tippy.js: 6.3.7 - '@tiptap/extension-gapcursor@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)': + '@tiptap/extension-gapcursor@2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))(@tiptap/pm@2.10.4)': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) - '@tiptap/pm': 2.10.3 + '@tiptap/core': 2.10.4(@tiptap/pm@2.10.4) + '@tiptap/pm': 2.10.4 - '@tiptap/extension-hard-break@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-hard-break@2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.10.4(@tiptap/pm@2.10.4) - '@tiptap/extension-heading@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-heading@2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.10.4(@tiptap/pm@2.10.4) - '@tiptap/extension-history@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)': + '@tiptap/extension-history@2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))(@tiptap/pm@2.10.4)': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) - '@tiptap/pm': 2.10.3 + '@tiptap/core': 2.10.4(@tiptap/pm@2.10.4) + '@tiptap/pm': 2.10.4 - '@tiptap/extension-horizontal-rule@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)': + '@tiptap/extension-horizontal-rule@2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))(@tiptap/pm@2.10.4)': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) - '@tiptap/pm': 2.10.3 + '@tiptap/core': 2.10.4(@tiptap/pm@2.10.4) + '@tiptap/pm': 2.10.4 - '@tiptap/extension-italic@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-italic@2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.10.4(@tiptap/pm@2.10.4) - '@tiptap/extension-link@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)': + '@tiptap/extension-link@2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))(@tiptap/pm@2.10.4)': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) - '@tiptap/pm': 2.10.3 + '@tiptap/core': 2.10.4(@tiptap/pm@2.10.4) + '@tiptap/pm': 2.10.4 linkifyjs: 4.1.3 - '@tiptap/extension-list-item@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-list-item@2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.10.4(@tiptap/pm@2.10.4) - '@tiptap/extension-ordered-list@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-ordered-list@2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.10.4(@tiptap/pm@2.10.4) - '@tiptap/extension-paragraph@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-paragraph@2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.10.4(@tiptap/pm@2.10.4) - '@tiptap/extension-strike@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-strike@2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.10.4(@tiptap/pm@2.10.4) - '@tiptap/extension-text-style@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-text-style@2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.10.4(@tiptap/pm@2.10.4) - '@tiptap/extension-text@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-text@2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.10.4(@tiptap/pm@2.10.4) - '@tiptap/pm@2.10.3': + '@tiptap/pm@2.10.4': dependencies: prosemirror-changeset: 2.2.1 prosemirror-collab: 1.3.1 @@ -10213,41 +10236,41 @@ snapshots: prosemirror-transform: 1.10.2 prosemirror-view: 1.37.0 - '@tiptap/react@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@tiptap/react@2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))(@tiptap/pm@2.10.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) - '@tiptap/extension-bubble-menu': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3) - '@tiptap/extension-floating-menu': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3) - '@tiptap/pm': 2.10.3 + '@tiptap/core': 2.10.4(@tiptap/pm@2.10.4) + '@tiptap/extension-bubble-menu': 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))(@tiptap/pm@2.10.4) + '@tiptap/extension-floating-menu': 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))(@tiptap/pm@2.10.4) + '@tiptap/pm': 2.10.4 '@types/use-sync-external-store': 0.0.6 fast-deep-equal: 3.1.3 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) use-sync-external-store: 1.2.2(react@18.3.1) - '@tiptap/starter-kit@2.10.3': - dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) - '@tiptap/extension-blockquote': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-bold': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-bullet-list': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-code': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-code-block': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3) - '@tiptap/extension-document': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-dropcursor': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3) - '@tiptap/extension-gapcursor': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3) - '@tiptap/extension-hard-break': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-heading': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-history': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3) - '@tiptap/extension-horizontal-rule': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3) - '@tiptap/extension-italic': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-list-item': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-ordered-list': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-paragraph': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-strike': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-text': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-text-style': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/pm': 2.10.3 + '@tiptap/starter-kit@2.10.4': + dependencies: + '@tiptap/core': 2.10.4(@tiptap/pm@2.10.4) + '@tiptap/extension-blockquote': 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4)) + '@tiptap/extension-bold': 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4)) + '@tiptap/extension-bullet-list': 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4)) + '@tiptap/extension-code': 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4)) + '@tiptap/extension-code-block': 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))(@tiptap/pm@2.10.4) + '@tiptap/extension-document': 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4)) + '@tiptap/extension-dropcursor': 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))(@tiptap/pm@2.10.4) + '@tiptap/extension-gapcursor': 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))(@tiptap/pm@2.10.4) + '@tiptap/extension-hard-break': 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4)) + '@tiptap/extension-heading': 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4)) + '@tiptap/extension-history': 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))(@tiptap/pm@2.10.4) + '@tiptap/extension-horizontal-rule': 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4))(@tiptap/pm@2.10.4) + '@tiptap/extension-italic': 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4)) + '@tiptap/extension-list-item': 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4)) + '@tiptap/extension-ordered-list': 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4)) + '@tiptap/extension-paragraph': 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4)) + '@tiptap/extension-strike': 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4)) + '@tiptap/extension-text': 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4)) + '@tiptap/extension-text-style': 2.10.4(@tiptap/core@2.10.4(@tiptap/pm@2.10.4)) + '@tiptap/pm': 2.10.4 '@tootallnate/once@2.0.0': {} @@ -10519,26 +10542,26 @@ snapshots: '@ungap/structured-clone@1.2.0': {} - '@urql/core@5.1.0(graphql@16.9.0)': + '@urql/core@5.1.0(graphql@16.10.0)': dependencies: - '@0no-co/graphql.web': 1.0.7(graphql@16.9.0) + '@0no-co/graphql.web': 1.0.7(graphql@16.10.0) wonka: 6.3.4 transitivePeerDependencies: - graphql - '@urql/exchange-auth@2.2.0(@urql/core@5.1.0(graphql@16.9.0))': + '@urql/exchange-auth@2.2.0(@urql/core@5.1.0(graphql@16.10.0))': dependencies: - '@urql/core': 5.1.0(graphql@16.9.0) + '@urql/core': 5.1.0(graphql@16.10.0) wonka: 6.3.4 - '@vitejs/plugin-react@4.3.4(vite@6.0.3(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5))': + '@vitejs/plugin-react@4.3.4(vite@6.0.4(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5))': dependencies: '@babel/core': 7.26.0 '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0) '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 - vite: 6.0.3(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5) + vite: 6.0.4(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5) transitivePeerDependencies: - supports-color @@ -10647,7 +10670,7 @@ snapshots: array-buffer-byte-length@1.0.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 is-array-buffer: 3.0.4 array-includes@3.1.8: @@ -10704,11 +10727,11 @@ snapshots: arraybuffer.prototype.slice@1.0.3: dependencies: array-buffer-byte-length: 1.0.1 - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.23.3 es-errors: 1.3.0 - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.6 is-array-buffer: 3.0.4 is-shared-array-buffer: 1.0.3 @@ -10911,6 +10934,11 @@ snapshots: dependencies: streamsearch: 1.1.0 + call-bind-apply-helpers@1.0.1: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + call-bind@1.0.7: dependencies: es-define-property: 1.0.0 @@ -10919,6 +10947,18 @@ snapshots: get-intrinsic: 1.2.4 set-function-length: 1.2.2 + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.1 + es-define-property: 1.0.1 + get-intrinsic: 1.2.6 + set-function-length: 1.2.2 + + call-bound@1.0.3: + dependencies: + call-bind-apply-helpers: 1.0.1 + get-intrinsic: 1.2.6 + callsites@3.1.0: {} camel-case@4.1.2: @@ -11261,19 +11301,19 @@ snapshots: data-view-buffer@1.0.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 is-data-view: 1.0.1 data-view-byte-length@1.0.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 is-data-view: 1.0.1 data-view-byte-offset@1.0.0: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 is-data-view: 1.0.1 @@ -11313,7 +11353,7 @@ snapshots: define-data-property@1.1.4: dependencies: - es-define-property: 1.0.0 + es-define-property: 1.0.1 es-errors: 1.3.0 gopd: 1.0.1 @@ -11421,6 +11461,12 @@ snapshots: dset@3.1.3: {} + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + eastasianwidth@0.2.0: {} ejs@3.1.10: @@ -11461,7 +11507,7 @@ snapshots: array-buffer-byte-length: 1.0.1 arraybuffer.prototype.slice: 1.0.3 available-typed-arrays: 1.0.7 - call-bind: 1.0.7 + call-bind: 1.0.8 data-view-buffer: 1.0.1 data-view-byte-length: 1.0.1 data-view-byte-offset: 1.0.0 @@ -11507,7 +11553,9 @@ snapshots: es-define-property@1.0.0: dependencies: - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.6 + + es-define-property@1.0.1: {} es-errors@1.3.0: {} @@ -12018,10 +12066,10 @@ snapshots: fraction.js@4.3.7: {} - framer-motion@11.14.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + framer-motion@11.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - motion-dom: 11.14.1 - motion-utils: 11.14.1 + motion-dom: 11.14.3 + motion-utils: 11.14.3 tslib: 2.8.0 optionalDependencies: react: 18.3.1 @@ -12045,7 +12093,7 @@ snapshots: function.prototype.name@1.1.6: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.23.3 functions-have-names: 1.2.3 @@ -12064,6 +12112,19 @@ snapshots: has-symbols: 1.0.3 hasown: 2.0.2 + get-intrinsic@1.2.6: + dependencies: + call-bind-apply-helpers: 1.0.1 + dunder-proto: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + function-bind: 1.1.2 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + get-nonce@1.0.1: {} get-package-type@0.1.0: {} @@ -12072,9 +12133,9 @@ snapshots: get-symbol-description@1.0.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.6 get-tsconfig@4.7.5: dependencies: @@ -12142,20 +12203,22 @@ snapshots: dependencies: get-intrinsic: 1.2.4 + gopd@1.2.0: {} + graceful-fs@4.2.11: {} graphemer@1.4.0: {} - graphql-config@5.1.3(@types/node@22.10.2)(graphql@16.9.0)(typescript@5.7.2): + graphql-config@5.1.3(@types/node@22.10.2)(graphql@16.10.0)(typescript@5.7.2): dependencies: - '@graphql-tools/graphql-file-loader': 8.0.1(graphql@16.9.0) - '@graphql-tools/json-file-loader': 8.0.1(graphql@16.9.0) - '@graphql-tools/load': 8.0.2(graphql@16.9.0) - '@graphql-tools/merge': 9.0.4(graphql@16.9.0) - '@graphql-tools/url-loader': 8.0.2(@types/node@22.10.2)(graphql@16.9.0) - '@graphql-tools/utils': 10.2.3(graphql@16.9.0) + '@graphql-tools/graphql-file-loader': 8.0.1(graphql@16.10.0) + '@graphql-tools/json-file-loader': 8.0.1(graphql@16.10.0) + '@graphql-tools/load': 8.0.2(graphql@16.10.0) + '@graphql-tools/merge': 9.0.4(graphql@16.10.0) + '@graphql-tools/url-loader': 8.0.2(@types/node@22.10.2)(graphql@16.10.0) + '@graphql-tools/utils': 10.2.3(graphql@16.10.0) cosmiconfig: 8.3.6(typescript@5.7.2) - graphql: 16.9.0 + graphql: 16.10.0 jiti: 2.3.3 minimatch: 9.0.5 string-env-interpolation: 1.0.1 @@ -12167,24 +12230,24 @@ snapshots: - typescript - utf-8-validate - graphql-request@6.1.0(graphql@16.9.0): + graphql-request@6.1.0(graphql@16.10.0): dependencies: - '@graphql-typed-document-node/core': 3.2.0(graphql@16.9.0) + '@graphql-typed-document-node/core': 3.2.0(graphql@16.10.0) cross-fetch: 3.1.8 - graphql: 16.9.0 + graphql: 16.10.0 transitivePeerDependencies: - encoding - graphql-tag@2.12.6(graphql@16.9.0): + graphql-tag@2.12.6(graphql@16.10.0): dependencies: - graphql: 16.9.0 + graphql: 16.10.0 tslib: 2.8.0 - graphql-ws@5.16.0(graphql@16.9.0): + graphql-ws@5.16.0(graphql@16.10.0): dependencies: - graphql: 16.9.0 + graphql: 16.10.0 - graphql@16.9.0: {} + graphql@16.10.0: {} has-bigints@1.0.2: {} @@ -12198,6 +12261,8 @@ snapshots: has-symbols@1.0.3: {} + has-symbols@1.1.0: {} + has-tostringtag@1.0.2: dependencies: has-symbols: 1.0.3 @@ -12351,13 +12416,13 @@ snapshots: is-arguments@1.1.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 has-tostringtag: 1.0.2 is-array-buffer@3.0.4: dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 + call-bind: 1.0.8 + get-intrinsic: 1.2.6 is-arrayish@0.2.1: {} @@ -12377,7 +12442,7 @@ snapshots: is-boolean-object@1.1.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 has-tostringtag: 1.0.2 is-bun-module@1.1.0: @@ -12404,7 +12469,7 @@ snapshots: is-finalizationregistry@1.0.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 is-fullwidth-code-point@3.0.0: {} @@ -12442,7 +12507,7 @@ snapshots: is-regex@1.1.4: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 has-tostringtag: 1.0.2 is-relative@1.0.0: @@ -12453,7 +12518,7 @@ snapshots: is-shared-array-buffer@1.0.3: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 is-stream@2.0.1: {} @@ -12463,7 +12528,7 @@ snapshots: is-symbol@1.0.4: dependencies: - has-symbols: 1.0.3 + has-symbols: 1.1.0 is-typed-array@1.1.13: dependencies: @@ -12483,12 +12548,12 @@ snapshots: is-weakref@1.0.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 is-weakset@2.0.3: dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 + call-bind: 1.0.8 + get-intrinsic: 1.2.6 is-windows@1.0.2: {} @@ -12972,9 +13037,10 @@ snapshots: json-stable-stringify-without-jsonify@1.0.1: {} - json-stable-stringify@1.1.1: + json-stable-stringify@1.2.0: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.3 isarray: 2.0.5 jsonify: 0.0.1 object-keys: 1.1.1 @@ -13181,6 +13247,8 @@ snapshots: punycode.js: 2.3.1 uc.micro: 2.1.0 + math-intrinsics@1.1.0: {} + mathml-tag-names@2.1.3: {} mdn-data@2.0.28: {} @@ -13234,9 +13302,9 @@ snapshots: minipass@7.1.2: {} - motion-dom@11.14.1: {} + motion-dom@11.14.3: {} - motion-utils@11.14.1: {} + motion-utils@11.14.3: {} ms@2.1.2: {} @@ -13306,7 +13374,7 @@ snapshots: object.assign@4.1.5: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 has-symbols: 1.0.3 object-keys: 1.1.1 @@ -13827,7 +13895,7 @@ snapshots: '@babel/runtime': 7.26.0 react: 18.3.1 - react-csv-downloader@3.1.1(react@18.3.1): + react-csv-downloader@3.2.0(react@18.3.1): dependencies: file-saver: 2.0.5 react: 18.3.1 @@ -13859,9 +13927,9 @@ snapshots: react-fast-compare@3.2.2: {} - react-focus-lock@2.13.2(@types/react@18.3.13)(react@18.3.1): + react-focus-lock@2.13.5(@types/react@18.3.13)(react@18.3.1): dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.26.0 focus-lock: 1.3.5 prop-types: 15.8.1 react: 18.3.1 @@ -13878,7 +13946,7 @@ snapshots: react-fast-compare: 3.2.2 shallowequal: 1.1.0 - react-hook-form@7.54.0(react@18.3.1): + react-hook-form@7.54.1(react@18.3.1): dependencies: react: 18.3.1 @@ -13906,21 +13974,21 @@ snapshots: react-refresh@0.14.2: {} - react-remove-scroll-bar@2.3.6(@types/react@18.3.13)(react@18.3.1): + react-remove-scroll-bar@2.3.8(@types/react@18.3.13)(react@18.3.1): dependencies: react: 18.3.1 - react-style-singleton: 2.2.1(@types/react@18.3.13)(react@18.3.1) + react-style-singleton: 2.2.3(@types/react@18.3.13)(react@18.3.1) tslib: 2.8.0 optionalDependencies: '@types/react': 18.3.13 - react-remove-scroll@2.6.0(@types/react@18.3.13)(react@18.3.1): + react-remove-scroll@2.6.2(@types/react@18.3.13)(react@18.3.1): dependencies: react: 18.3.1 - react-remove-scroll-bar: 2.3.6(@types/react@18.3.13)(react@18.3.1) - react-style-singleton: 2.2.1(@types/react@18.3.13)(react@18.3.1) - tslib: 2.6.3 - use-callback-ref: 1.3.2(@types/react@18.3.13)(react@18.3.1) + react-remove-scroll-bar: 2.3.8(@types/react@18.3.13)(react@18.3.1) + react-style-singleton: 2.2.3(@types/react@18.3.13)(react@18.3.1) + tslib: 2.8.0 + use-callback-ref: 1.3.3(@types/react@18.3.13)(react@18.3.1) use-sidecar: 1.1.2(@types/react@18.3.13)(react@18.3.1) optionalDependencies: '@types/react': 18.3.13 @@ -13935,10 +14003,9 @@ snapshots: optionalDependencies: react-dom: 18.3.1(react@18.3.1) - react-style-singleton@2.2.1(@types/react@18.3.13)(react@18.3.1): + react-style-singleton@2.2.3(@types/react@18.3.13)(react@18.3.1): dependencies: get-nonce: 1.0.1 - invariant: 2.2.4 react: 18.3.1 tslib: 2.8.0 optionalDependencies: @@ -13988,11 +14055,11 @@ snapshots: reflect.getprototypeof@1.0.6: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.23.3 es-errors: 1.3.0 - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.6 globalthis: 1.0.4 which-builtin-type: 1.1.3 @@ -14000,7 +14067,7 @@ snapshots: regexp.prototype.flags@1.5.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-errors: 1.3.0 set-function-name: 2.0.2 @@ -14108,7 +14175,7 @@ snapshots: safe-array-concat@1.1.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 get-intrinsic: 1.2.4 has-symbols: 1.0.3 isarray: 2.0.5 @@ -14154,8 +14221,8 @@ snapshots: define-data-property: 1.1.4 es-errors: 1.3.0 function-bind: 1.1.2 - get-intrinsic: 1.2.4 - gopd: 1.0.1 + get-intrinsic: 1.2.6 + gopd: 1.2.0 has-property-descriptors: 1.0.2 set-function-name@2.0.2: @@ -14179,7 +14246,7 @@ snapshots: side-channel@1.0.6: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 get-intrinsic: 1.2.4 object-inspect: 1.13.2 @@ -14320,7 +14387,7 @@ snapshots: string.prototype.trim@1.2.9: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.23.3 es-object-atoms: 1.0.0 @@ -14333,7 +14400,7 @@ snapshots: string.prototype.trimstart@1.0.8: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-object-atoms: 1.0.0 @@ -14656,13 +14723,13 @@ snapshots: typed-array-buffer@1.0.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 is-typed-array: 1.1.13 typed-array-byte-length@1.0.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 for-each: 0.3.3 gopd: 1.0.1 has-proto: 1.0.3 @@ -14671,7 +14738,7 @@ snapshots: typed-array-byte-offset@1.0.2: dependencies: available-typed-arrays: 1.0.7 - call-bind: 1.0.7 + call-bind: 1.0.8 for-each: 0.3.3 gopd: 1.0.1 has-proto: 1.0.3 @@ -14679,7 +14746,7 @@ snapshots: typed-array-length@1.0.6: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 for-each: 0.3.3 gopd: 1.0.1 has-proto: 1.0.3 @@ -14705,7 +14772,7 @@ snapshots: unbox-primitive@1.0.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 has-bigints: 1.0.2 has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 @@ -14764,9 +14831,9 @@ snapshots: urlpattern-polyfill@10.0.0: {} - urql@4.2.1(@urql/core@5.1.0(graphql@16.9.0))(react@18.3.1): + urql@4.2.1(@urql/core@5.1.0(graphql@16.10.0))(react@18.3.1): dependencies: - '@urql/core': 5.1.0(graphql@16.9.0) + '@urql/core': 5.1.0(graphql@16.10.0) react: 18.3.1 wonka: 6.3.4 @@ -14777,6 +14844,13 @@ snapshots: optionalDependencies: '@types/react': 18.3.13 + use-callback-ref@1.3.3(@types/react@18.3.13)(react@18.3.1): + dependencies: + react: 18.3.1 + tslib: 2.8.0 + optionalDependencies: + '@types/react': 18.3.13 + use-sidecar@1.1.2(@types/react@18.3.13)(react@18.3.1): dependencies: detect-node-es: 1.1.0 @@ -14811,15 +14885,15 @@ snapshots: value-or-promise@1.0.12: {} - vite-plugin-compression2@1.3.3(rollup@4.27.4)(vite@6.0.3(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5)): + vite-plugin-compression2@1.3.3(rollup@4.27.4)(vite@6.0.4(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5)): dependencies: '@rollup/pluginutils': 5.1.0(rollup@4.27.4) tar-mini: 0.2.0 - vite: 6.0.3(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5) + vite: 6.0.4(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5) transitivePeerDependencies: - rollup - vite-plugin-html@3.2.2(vite@6.0.3(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5)): + vite-plugin-html@3.2.2(vite@6.0.4(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5)): dependencies: '@rollup/pluginutils': 4.2.1 colorette: 2.0.20 @@ -14833,9 +14907,9 @@ snapshots: html-minifier-terser: 6.1.0 node-html-parser: 5.4.2 pathe: 0.2.0 - vite: 6.0.3(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5) + vite: 6.0.4(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5) - vite@6.0.3(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5): + vite@6.0.4(@types/node@22.10.2)(jiti@2.3.3)(lightningcss@1.25.1)(terser@5.31.1)(tsx@4.19.2)(yaml@2.4.5): dependencies: esbuild: 0.24.0 postcss: 8.4.49 @@ -14922,7 +14996,7 @@ snapshots: which-typed-array@1.1.15: dependencies: available-typed-arrays: 1.0.7 - call-bind: 1.0.7 + call-bind: 1.0.8 for-each: 0.3.3 gopd: 1.0.1 has-tostringtag: 1.0.2