Conversation
… and collection Introduce SegmentMetadataMarshaller enum as single source of truth for valid metadata keys with marshall/unmarshall type conversion. Add SegmentMetadataMapper to map XLIFF trans-unit attributes to DB-ready SegmentMetadataStruct entries, and SegmentMetadataCollection as a purpose-built read-only collection with typed find() lookup. Refactor all consumers (SegmentExtractor, SegmentStorageService, SizeRestrictionChecker, QA, controllers) to use the centralized components instead of scattered constants and inline logic.
… returns collection, API serves typed values
…Type enum Add resname and restype attributes to the segment metadata pipeline, enabling XLIFF context mapping storage with validated lookup strategies.
GetSegmentsController now calls jsonSerialize() on SegmentMetadataCollection, returning typed values (int, string) instead of raw DB strings.
- Add proper error reporting: check isValid() and throw with aggregated exception messages instead of silently accepting invalid metadata - Remove unused imports (InjectableFiltersTags, HandlersSorter, JobsMetadataDao, MetadataDao)
…nstraints - XLIFF 2.0 test fixture: use matecat: namespace prefix (matecat:resname, matecat:restype) with proper xmlns:matecat declaration per spec - Feature spec Section 8: clean constraints from 16 → 13 active items, remove implemented/outdated entries, add new architecture decisions
- Section 7.2: context-url pipeline task list (7 items) — FilesMetadataMarshaller, CONTEXT_URL cases, fallback resolver, 3 APIs, GetSegmentsController - Section 11: full architecture — three-level storage, dual ingestion paths, read-time fallback resolution, FilesMetadataMarshaller Pattern B design - Section 8: three new constraints (naming convention, dual ingestion, fallback order)
…aStruct value as mixed
…lers Add 'context-url' as a new metadata key recognized at both segment level (SegmentMetadataMarshaller, 9th case) and project level (ProjectsMetadataMarshaller, 31st case). Both use simple string pass-through for marshall/unMarshall. TDD: +8 tests.
…hModel and UserDao - parameterize status, job, and password in all 3 SearchModel query builders - remove dead regexp-escape assignments (regexpEscapedSrc/Trg never read) - remove redundant escape() in UserDao::sanitize(), downstream queries already use :named PDO parameters
…Statement() - Change buildInsertStatement() return type from string to array - Return [$sql, $dupBindValues] to surface bind values to callers - Update Database::insert() to merge dupBindValues before execute() - Update AbstractDao::insertStruct() to merge dupBindValues into data - Add 6 unit tests + 4 integration tests covering all branches - Mark TF-1 as done in remaining-actionable-items.md
…ions, type propagateTranslation, remove dead escape() QW-3: Replace $_POST direct access with $this->params in FilesController, DeepLGlossaryController, and ModernMTController (16 replacements across 3 files). Replace $_FILES direct access with Klein $this->request->files() DataCollection in XliffToTargetConverterController, ModernMTController, DeepLGlossaryController, TMXFileController, and GlossaryFilesController. Refactor TMSService::uploadFile() to accept injected file array. Add constructor injection to UploadHandler for file array (single boundary: index.php passes $_FILES). QW-4: Add @return array shape docblock to VersionHandlerInterface::propagateTranslation(). QW-2 cleanup: Remove dead escape() method from Database.php and IDatabase.php after all callers were migrated to parameterized queries. All tests pass: 2278 tests, 17481 assertions, 0 failures.
…rglobals with Klein abstractions in 6 controllers
…b->commit(), fix PHPStan level 8 TF-3: Decompose the 279-line SetTranslationController::translate() into 5 focused private methods (prepareTranslation, buildNewTranslation, persistTranslation, buildResult, finalizeTranslation) with transaction boundaries ($db->begin/$db->commit) visible in the orchestrator. Post-extraction: removed Database $db from persistTranslation() params, fixed all 80 PHPStan level 8 errors including filter_var string|false handling, nullable property guards, typed method signatures, and accurate array shape PHPDocs. 25 unit tests for canUpdateSuggestion (10), isSplittedSegment (4), setStatusForSplittedSegment (3), buildNewTranslation (8) via TestableSetTranslationController subclass + 6 structural guards. 2310 tests, 17701 assertions, 0 failures. PHPStan level 8: 0 errors.
…tureStruct, and OwnerFeatureDao - Type __construct($features) param as ?array<BasicFeatureStruct> - Add iterable value types to getCodes(), splitString(), getAutoloadPlugins(), merge(), runOnFeature() - Narrow BasicFeatureStruct::toNewObject() return from IBaseFeature to BaseFeature - Replace call_user_func_array() with first-class callable syntax ($obj->$method(...$args)) - Remove dead property_exists() check (always true for typed BasicFeatureStruct) - Fix OwnerFeatureDao: narrow getByIdCustomer/getByUserId return types, type destroyCacheByIdCustomer param, cast lastInsertId to int, remove dead ?? [] (non-nullable _fetchObjectMap) - Type BasicFeatureStruct::$options as array<string, mixed>|string|null
…ming convention - Align rewriteContributionContexts @method param $contextData → $requestData - Reclassify filterProjectNameModified, handleTUContextGroups, alter_chunk_review_struct from filter → run (return values were discarded) - Move @method annotations to run section with void return type - Document hook naming convention: ~45 camelCase vs ~17 snake_case, policy: keep existing, new hooks use camelCase (PSR-1) - Update roadmap inconsistencies section with resolutions - Update remaining-actionable-items.md SR-5 status
…case to camelCase Remove 20 hook dispatch sites that have zero handler implementations across all plugins (uber, airbnb, translated, aligner) and internal features. Rename 5 remaining snake_case hooks to camelCase for PSR-1 consistency. Removed hooks (filter): filterCreationStatus, overrideConversionResult, filterGlobalWarnings, filterSegmentWarnings, filterSetTranslationResult, prepareAllNotes, processExtractedJsonNotes, filterIsChunkCompletionUndoable, doNotManageAlternativeTranslations, filter_team_for_project_creation, filterProjectDependencies, filterFeaturesMerged Removed hooks (run): project_password_changed, processZIPDownloadPreview, checkSplitAccess, afterTMAnalysisCloseProject, fastAnalysisComplete, bootstrapCompleted, postProjectCommit, handleTUContextGroups Renamed: filter_job_password_to_review_password → filterJobPasswordToReviewPassword, job_password_changed → jobPasswordChanged, review_password_changed → reviewPasswordChanged, project_completion_event_saved → projectCompletionEventSaved, alter_chunk_review_struct → alterChunkReviewStruct
…et hooks - Add FilterEvent/RunEvent minimal base classes (single hookName() method) - Add dispatchFilter()/dispatchRun() on FeatureSet with matching error handling - Create 44 typed event DTO classes (29 filter + 15 run) in Hook/Event/ - Migrate all 44 call sites from string filter()/run() to typed dispatchFilter()/dispatchRun() - Migrate all handler methods in Uber, Airbnb, Translated, AbstractRevisionFeature, ProjectCompletion - Remove @method annotations from FeatureSet (superseded by event classes) - Clean stale handler docblocks, remove union type hacks from Translated - Add @see dispatch-site annotations on all 43 event classes - Add @template T on dispatchFilter()/dispatchRun() for PHPStan inference - Extract Translated::checkInternalEmail() static utility from hook handler - Add phpstan.neon with bootstrap autoloader for plugin analysis - Fix 58 PHPStan missingType errors with annotations (no code changes) - Fix 8 PHPStan doc-only errors (@var/@return/@param type narrowing) - Fix 15 PHPStan code errors in Airbnb plugin (false guards, null coalesce, dead code) - Fix 7 PHPUnit notices (createMock → createStub where no expectations set) - Legacy filter()/run() retained only for 5 vendor SubFiltering hooks No BC bridge — all plugins controlled, handlers updated atomically per-hook. Zero string dispatch remaining in lib/ (verified via grep). 2323 tests, 0 failures, 0 notices.
…ed plugins Airbnb: 19 → 4 errors (15 fixed, 4 require interface/struct changes in lib/) Translated: 16 → 0 errors (all fixed) 2323 tests, 0 failures.
…yped pipeline customization - Implement 6 customizeFrom*() methods on FeatureSet (FeatureSetInterface v4.0) - customizeFromLayer0ToLayer1 wraps event dispatch (Uber + Airbnb handlers) - Other 5 are no-ops (YAGNI — no handlers exist) - Delete filter(string, mixed): mixed - Delete run(string): void - Delete runOnFeature() private helper - Migrate Uber + Airbnb fromLayer0ToLayer1 handlers to event DTO (was still Pipeline) - Remove reflection bridge added by subagent — clean direct dispatch only Zero string dispatch remaining. 2325 tests, 0 failures.
- Add screenshot metadata extraction to contextReviewUtils - Create HtmlContextPanel and ScreenshotContextPanel components - Implement zoom controls (50%-200%) for both HTML and screenshot views - Add toolbar toggle to switch between HTML and screenshot content views - Fix scrolling behavior for zoomed content in both views - Prevent nested scrollbars in HTML view with overflow:visible enforcement - Add responsive zoom with dynamic margin for proper scroll bounds - All 235 tests passing
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Rename all frontend JS/SCSS files, utilities, hooks, components, and sample files from context-review to context-preview. Add _context_preview.html template (served via the existing /context-review route) with updated body/div class names matching the renamed frontend selectors. Webpack entry point updated accordingly.
…calls On incremental calls to tagSegments, tier1 elements (resolved via the strategy pass using resname/restype) were not added to tier1Nodes. This allowed Pass 2 to append other segments to those elements via text match, causing tier1 segments to appear on multiple nodes and showing spurious navigation buttons. Fix: in the alreadyTagged branch of the strategy pass, re-find the element via findElementByMetadata and add it to tier1Nodes so Pass 2 correctly excludes it on subsequent calls. Add regression test covering the incremental call scenario.
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds a “context preview/review” capability and modernizes several backend/plugin hook integrations by introducing typed hook event objects, while also cleaning up legacy test assets and tightening data-handling in a few critical paths.
Changes:
- Introduce Context Preview UI building blocks (new panels, resizing hook, layout styles) and wire segment highlight/translation updates to a ContextPreview channel.
- Replace multiple FeatureSet
filter()/run()calls with typeddispatchFilter()/dispatchRun()events across controllers, workers, and LQA components. - Update segment/file/project metadata handling (new metadata marshallers/collections, context-url support) and enforce a unique constraint on
segment_metadata.
Reviewed changes
Copilot reviewed 268 out of 328 changed files in this pull request and generated 15 comments.
Show a summary per file
| File | Description |
|---|---|
| public/js/hooks/useSegmentsLoader.js | Remove unused import from segments loader hook. |
| public/js/hooks/useResizable.js | New hook for draggable vertical resizing. |
| public/js/components/segments/utils/DraftMatecatUtils/tagUtils.js | Adjust tag placeholder handling during text transform. |
| public/js/components/segments/SegmentsContainer.js | Recalculate viewport height with context preview wrapper + send highlight messages. |
| public/js/components/segments/Editarea.js | Send translation updates to context preview channel. |
| public/js/components/contextPreview/index.js | Export context preview panels. |
| public/js/components/contextPreview/ScreenshotContextPanel.js | New screenshot-based context preview panel. |
| public/js/components/contextPreview/LivePreviewPanel.js | New live preview container panel with zoom scaling. |
| public/img/icons/ChangePassword.js | Fix React SVG attribute casing (clipPath). |
| public/css/sass/cattool.scss | Add context preview header/container/resize-handle styles. |
| plugins/uber | Bump submodule pointer. |
| plugins/translated | Bump submodule pointer. |
| plugins/airbnb | Bump submodule pointer. |
| phpstan.neon | Add PHPStan configuration. |
| old_tests/support/lib/Utils/ZipArchiveExtendedTest.php | Remove legacy test placeholder. |
| old_tests/support/lib/UnitTestInitializer.php | Remove legacy integration test initializer. |
| old_tests/support/lib/IntegrationTest.php | Remove legacy integration test base class. |
| old_tests/support/lib/Factory/User.php | Remove legacy factory. |
| old_tests/support/lib/Factory/OwnerFeature.php | Remove legacy factory. |
| old_tests/support/lib/Factory/Base.php | Remove legacy factory base. |
| old_tests/support/lib/Factory/ApiKey.php | Remove legacy factory. |
| old_tests/support/fixtures/users.yml | Remove legacy fixtures. |
| old_tests/support/fixtures/segments.yml | Remove legacy fixtures. |
| old_tests/support/fixtures/segment_translations.yml | Remove legacy fixtures. |
| old_tests/support/fixtures/segment_translation_versions.yml | Remove legacy fixtures. |
| old_tests/support/fixtures/qa_models.yml | Remove legacy fixtures. |
| old_tests/support/fixtures/qa_chunk_reviews.yml | Remove legacy fixtures. |
| old_tests/support/fixtures/qa_categories.yml | Remove legacy fixtures. |
| old_tests/support/fixtures/projects.yml | Remove legacy fixtures. |
| old_tests/support/fixtures/jobs.yml | Remove legacy fixtures. |
| old_tests/support/fixtures/files_job.yml | Remove legacy fixtures. |
| old_tests/support/fixtures/files.yml | Remove legacy fixtures. |
| old_tests/support/files/zip-with-model-json/amex-test.docx.xlf | Remove legacy test file. |
| old_tests/support/files/zip-with-model-json/__meta/qa_model.json | Remove legacy test metadata file. |
| old_tests/support/files/xliff/sdlxliff-with-mrk-and-note.xlf.sdlxliff | Remove legacy test file. |
| old_tests/support/files/xliff/file-with-preserve-white-space.xliff | Remove legacy test file. |
| old_tests/support/files/xliff/file-with-notes-nobase64.po.sdlxliff | Remove legacy test file. |
| old_tests/support/files/xliff/file-with-hello-world.xliff | Remove legacy test file. |
| old_tests/support/files/xliff/amex-test.docx.xlf | Remove legacy test file. |
| old_tests/support/files/txt/hello.txt | Remove legacy test file. |
| old_tests/support/files/tmx/exampleForTestOriginal.tmx | Remove legacy test file. |
| old_tests/support/files/test-propagation.xlf | Remove legacy test file. |
| old_tests/support/files/small-with-notes.sdlxliff | Remove legacy test file. |
| old_tests/support/files/json/schema/schema_1.json | Remove legacy schema fixture. |
| old_tests/support/files/json/schema/invalid.json | Remove legacy invalid schema fixture. |
| old_tests/support/files/json/files/valid.json | Remove legacy JSON fixture. |
| old_tests/support/files/json/files/invalid_maxItems.json | Remove legacy JSON fixture. |
| old_tests/support/files/json/files/invalid.json | Remove legacy JSON fixture. |
| old_tests/support/files/glossary/GlossaryInvalidHeader.csv | Remove legacy glossary fixture. |
| old_tests/support/files/glossary/Final-Matecat-new_glossary_format-InvalidTargetLang.csv | Remove legacy glossary fixture. |
| old_tests/support/files/glossary/Final-Matecat-new_glossary_format-Glossary.csv | Remove legacy glossary fixture. |
| old_tests/support/files/csv/glossary/mixed-valid.csv | Remove legacy glossary fixture. |
| old_tests/support/files/csv/glossary/minimal-valid.csv | Remove legacy glossary fixture. |
| old_tests/support/files/csv/glossary/minimal-invalid.csv | Remove legacy glossary fixture. |
| old_tests/support/files/csv/glossary/invalid-structure.csv | Remove legacy glossary fixture. |
| old_tests/support/files/csv/glossary/invalid-language.csv | Remove legacy glossary fixture. |
| old_tests/support/files/csv/glossary/full-structure-valid.csv | Remove legacy glossary fixture. |
| old_tests/support/files/csv/glossary/V - Header-vuoti.csv | Remove legacy glossary fixture. |
| old_tests/support/files/csv/glossary/V - Formato solo blacklist language-specific.csv | Remove legacy glossary fixture. |
| old_tests/support/files/csv/glossary/V - Formato solo blacklist combinata.csv | Remove legacy glossary fixture. |
| old_tests/support/files/csv/glossary/V - Formato semplice solo lingue.csv | Remove legacy glossary fixture. |
| old_tests/support/files/csv/glossary/V - Formato lingue + campi termine.csv | Remove legacy glossary fixture. |
| old_tests/support/files/csv/glossary/V - Formato lingue + campi termine (non per tutte le lingue).csv | Remove legacy glossary fixture. |
| old_tests/support/files/csv/glossary/V - Formato completo.csv | Remove legacy glossary fixture. |
| old_tests/support/files/csv/glossary/NV -Formato solo blacklist generale.csv | Remove legacy glossary fixture. |
| old_tests/support/files/csv/glossary/NV - Header vuoto.csv | Remove legacy glossary fixture. |
| old_tests/support/files/csv/glossary/NV - Formato una sola lingua solo note.csv | Remove legacy glossary fixture. |
| old_tests/support/files/csv/glossary/NV - Formato una sola lingua solo esempi.csv | Remove legacy glossary fixture. |
| old_tests/support/files/csv/glossary/NV - Formato una sola lingua completa.csv | Remove legacy glossary fixture. |
| old_tests/support/files/csv/glossary/NV - Formato completo con colonne lingua spostate.csv | Remove legacy glossary fixture. |
| old_tests/support/files/csv/glossary/NV - Formato campi concetto + una sola lingua.csv | Remove legacy glossary fixture. |
| old_tests/support/files/csv/glossary/NV - Formato campi concetto + una sola lingua solo note.csv | Remove legacy glossary fixture. |
| old_tests/support/files/csv/glossary/NV - Formato campi concetto + una sola lingua solo esempi.csv | Remove legacy glossary fixture. |
| old_tests/support/files/csv/glossary/NV - Campi concetto + una sola lingua solo termini.csv | Remove legacy glossary fixture. |
| old_tests/integration/Features/TranslationVersions/setTranslationWithVersioningDisabledTest.php | Remove legacy integration test. |
| old_tests/integration/Features/ReviewImproved/AssignQualityModelToProjectTest.php | Remove legacy integration test. |
| old_tests/integration/Features/ProjectCompletion/JobStatusTest.php | Remove legacy integration test. |
| old_tests/integration/CreateProjectController/sourceAndTargetLangValidationTest.php | Remove legacy integration test. |
| old_tests/integration/CreateProjectController/setPrivateTMKeyTest.php | Remove legacy integration test. |
| old_tests/integration/Converters/ConversionsTest.php | Remove legacy integration test. |
| old_tests/integration/API/V2/SegmentVersionTest.php | Remove legacy integration test. |
| old_tests/integration/API/V2/SegmentTranslationIssueTest.php | Remove legacy integration test placeholder. |
| old_tests/integration/API/V2/ProjectUrlsTest.php | Remove legacy integration test. |
| old_tests/integration/API/V2/ProjectUpdateTest.php | Remove legacy integration test. |
| old_tests/integration/API/V2/JobMergeTest.php | Remove legacy integration test. |
| old_tests/integration/API/V2/CreateTeamTest.php | Remove legacy integration test. |
| old_tests/integration/API/V1/ValidateSourceAndTargetLanguagesTest.php | Remove legacy integration test. |
| old_tests/integration/API/V1/StatusTest.php | Remove legacy integration test. |
| old_tests/integration/API/V1/NewWithTeamTest.php | Remove legacy integration test. |
| old_tests/integration/API/V1/NewWithRevisionTypeTest.php | Remove legacy integration test. |
| old_tests/integration/API/V1/NewWithPrivateTMKeyTest.php | Remove legacy integration test. |
| old_tests/integration/API/V1/NewWithOwnershipTest.php | Remove legacy integration test. |
| old_tests/README.md | Remove legacy test documentation. |
| old_tests/.htaccess | Remove legacy directory access restriction file. |
| migrations/20260326190000_alter_table_segment_metadata_add_unique_index.php | Add migration for unique segment metadata key per segment. |
| lib/View/templates/_context_preview.html | Add new context preview view template. |
| lib/View/fileupload/index.php | Instantiate upload handler with injected files array. |
| lib/View/fileupload/UploadHandler.php | Decouple upload handler from superglobals by injecting files. |
| lib/View/API/V2/Json/Job.php | Use typed hook events for outsource info + project URLs. |
| lib/View/API/V2/Json/Activity.php | Use typed hook event for activity log entry filtering. |
| lib/View/API/App/Json/Analysis/AnalysisFile.php | Guard/encode non-string metadata keys/values. |
| lib/Utils/TMS/TMSService.php | Accept request files array instead of using $_FILES. |
| lib/Utils/LQA/SizeRestriction/SizeRestriction.php | Use typed event for character length counting. |
| lib/Utils/LQA/QA/TagChecker.php | Use typed events for tag mismatch/position checks. |
| lib/Utils/LQA/QA/SizeRestrictionChecker.php | Use metadata marshaller constant for size restriction key. |
| lib/Utils/LQA/QA/DomHandler.php | Use typed event for excluded tags injection. |
| lib/Utils/LQA/QA.php | Remove legacy constant alias for size restriction. |
| lib/Utils/Engines/MyMemory.php | Use typed event for MyMemory parameter filtering. |
| lib/Utils/AsyncTasks/Workers/Analysis/TMAnalysisWorker.php | Use typed event for analysis-before-MT hook; remove after-close-project hook. |
| lib/Utils/AsyncTasks/Workers/Analysis/FastAnalysis.php | Use typed run event; remove fast-analysis completion hook. |
| lib/Utils/AsyncTasks/Workers/AIAssistantWorker.php | Clean up comment and blank line. |
| lib/Utils/AIAssistant/GeminiClient.php | Remove unused AppConfig import. |
| lib/Routes/view_routes.php | Add route for context preview view. |
| lib/Routes/api_v3_routes.php | Add API v3 endpoints for context-url configuration. |
| lib/Plugins/Features/TranslationVersions/VersionHandlerInterface.php | Clarify return array shape in docblock. |
| lib/Plugins/Features/ReviewExtended/ReviewedWordCountModel.php | Use typed event for revision-change email filtering. |
| lib/Plugins/Features/ReviewExtended/ChunkReviewModel.php | Use typed run event for chunk review updates. |
| lib/Plugins/Features/ProjectCompletion/Model/ProjectCompletionStatusModel.php | Use typed event for review password mapping. |
| lib/Plugins/Features/ProjectCompletion/Model/EventModel.php | Use typed run event on completion event save. |
| lib/Plugins/Features/ProjectCompletion.php | Switch to typed hook event methods for job password + translation events. |
| lib/Model/matecat.sql | Make segment_metadata index unique in schema. |
| lib/Model/Users/UserDao.php | Add result type checks; remove legacy escaping. |
| lib/Model/Translators/TranslatorsModel.php | Dispatch typed job-password-changed run event. |
| lib/Model/Segments/SegmentUIStruct.php | Add context_url to UI struct. |
| lib/Model/Segments/SegmentMetadataMarshaller.php | New enum for allowed segment metadata keys and marshalling rules. |
| lib/Model/Segments/SegmentMetadataMapper.php | Map trans-unit attributes into metadata collection. |
| lib/Model/Segments/SegmentMetadataCollection.php | New collection helper for segment metadata. |
| lib/Model/Segments/ContextUrlResolver.php | Resolve segment/file/project-level context URL precedence. |
| lib/Model/Segments/ContextResType.php | Add enum for context resource type. |
| lib/Model/Projects/ProjectsMetadataMarshaller.php | Add project-level context-url metadata. |
| lib/Model/ProjectCreation/SegmentStorageService.php | Store segment metadata via collection; replace hooks with typed events. |
| lib/Model/ProjectCreation/ProjectManagerModel.php | Use SegmentMetadataMarshaller allowlist for segment metadata detection. |
| lib/Model/ProjectCreation/JobCreationService.php | Use typed events for payable rates and job creation validation. |
| lib/Model/OwnerFeatures/OwnerFeatureDao.php | Tighten types; remove null coalescing defaults; adjust signatures. |
| lib/Model/JobSplitMerge/JobSplitMergeService.php | Dispatch typed run events post-split and post-merge. |
| lib/Model/Files/MetadataStruct.php | Allow mixed values for file metadata. |
| lib/Model/Files/FilesMetadataMarshaller.php | New enum for allowed file metadata keys and marshalling. |
| lib/Model/FeaturesBase/Hook/RunEvent.php | New base class for typed run hook events. |
| lib/Model/FeaturesBase/Hook/FilterEvent.php | New base class for typed filter hook events. |
| lib/Model/FeaturesBase/Hook/Event/Run/ValidateProjectCreationEvent.php | New run hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Run/ValidateJobCreationEvent.php | New run hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Run/TmAnalysisDisabledEvent.php | New run hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Run/SetTranslationCommittedEvent.php | New run hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Run/ReviewPasswordChangedEvent.php | New run hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Run/ProjectCompletionEventSavedEvent.php | New run hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Run/PostProjectCreateEvent.php | New run hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Run/PostJobSplittedEvent.php | New run hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Run/PostJobMergedEvent.php | New run hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Run/PostAddSegmentTranslationEvent.php | New run hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Run/JobPasswordChangedEvent.php | New run hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Run/FilterProjectNameModifiedEvent.php | New run hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Run/ChunkReviewUpdatedEvent.php | New run hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Run/BeforeProjectCreationEvent.php | New run hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Run/AlterChunkReviewStructEvent.php | New run hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/WordCountEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/SanitizeOriginalDataMapEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/RewriteContributionContextsEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/ProjectUrlsEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/PrepareNotesForRenderingEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/PopulatePreTranslationsEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/OutsourceAvailableInfoEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/IsAnInternalUserEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/InjectExcludedTagsInQaEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/HandleJsonNotesBeforeInsertEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/FromLayer0ToLayer1Event.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/FilterRevisionChangeNotificationListEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/FilterPayableRatesEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/FilterMyMemoryGetParametersEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/FilterJobPasswordToReviewPasswordEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/FilterGetSegmentsResultEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/FilterCreateProjectFeaturesEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/FilterContributionStructOnSetTranslationEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/FilterContributionStructOnMTSetEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/FilterActivityLogEntryEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/EncodeInstructionsEvent | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/DecodeInstructionsEvent | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/CorrectTagErrorsEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/CheckTagPositionsEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/CheckTagMismatchEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/CharacterLengthCountEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/AppendInitialTemplateVarsEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/AppendFieldToAnalysisObjectEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/Hook/Event/Filter/AnalysisBeforeMTGetContributionEvent.php | New filter hook event class. |
| lib/Model/FeaturesBase/BasicFeatureStruct.php | Tighten options docblock and return type. |
| lib/Model/DataAccess/XFetchEnvelope.php | Add value object for XFetch cache metadata. |
| lib/Model/DataAccess/IDatabase.php | Remove legacy escape() method. |
| lib/Model/DataAccess/Database.php | Fix ON DUPLICATE KEY UPDATE binding + remove escape(). |
| lib/Model/DataAccess/AbstractDao.php | Track query compute delta and propagate duplicate bind values. |
| lib/Model/Conversion/Upload.php | Update docs to use request files array. |
| lib/Model/Analysis/AbstractStatus.php | Use typed outsource-available event. |
| lib/Controller/Views/OutsourceTo/AbstractController.php | Avoid logging raw superglobals; log request params. |
| lib/Controller/Views/ContextReviewController.php | New view controller for context preview route. |
| lib/Controller/Views/CattoolController.php | Use typed event for template vars hook. |
| lib/Controller/Views/AnalyzeController.php | Use typed event for template vars hook. |
| lib/Controller/Abstracts/BaseKleinViewController.php | Use typed internal-user filter hook event. |
| lib/Controller/Abstracts/Authentication/SessionTokenStoreHandler.php | Disable XFetch semantics for session tokens. |
| lib/Controller/API/V3/FileInfoController.php | Use typed decode-instructions event. |
| lib/Controller/API/V3/DeepLGlossaryController.php | Avoid $_POST/$_FILES; use request object. |
| lib/Controller/API/V2/UrlsController.php | Use typed project URLs event. |
| lib/Controller/API/V2/SplitJobController.php | Simplify split access check signature; remove feature hook call. |
| lib/Controller/API/V2/ProjectCreationStatusController.php | Remove plugin filtering of creation status result. |
| lib/Controller/API/V2/GlossaryFilesController.php | Pass request files array into uploadFile(). |
| lib/Controller/API/V2/DownloadOriginalController.php | Avoid logging raw $_POST; log request post params. |
| lib/Controller/API/V2/DownloadController.php | Remove conversion override hook and zip preview hook; avoid logging $_REQUEST. |
| lib/Controller/API/V2/ChangeProjectNameController.php | Dispatch typed run event instead of filter. |
| lib/Controller/API/V2/ChangePasswordController.php | Dispatch typed job/review password changed run events; remove project password hook. |
| lib/Controller/API/V1/NewController.php | Replace several hooks with typed events; adjust metadata validation. |
| lib/Controller/API/Commons/Validators/IsOwnerInternalUserValidator.php | Use typed internal-user event; improve readability. |
| lib/Controller/API/Commons/Validators/InternalUserValidator.php | Use typed internal-user event; improve readability. |
| lib/Controller/API/App/XliffToTargetConverterController.php | Use request files array instead of $_FILES. |
| lib/Controller/API/App/TMXFileController.php | Pass request files into uploadFile(). |
| lib/Controller/API/App/GetWarningController.php | Remove feature-driven warning filters and size restriction lookup change. |
| lib/Controller/API/App/GetTagProjectionController.php | Avoid logging raw $_POST. |
| lib/Controller/API/App/GetSearchController.php | Dispatch typed set-translation-committed event; normalize queryParams type. |
| lib/Controller/API/App/GetContributionController.php | Convert rewriteContributionContexts hook to typed event. |
| lib/Controller/API/App/FilesController.php | Avoid $_POST; use controller params. |
| lib/Controller/API/App/CreateProjectController.php | Convert filterCreateProjectFeatures hook to typed event. |
| lib/Controller/API/App/CompletionEventController.php | Load features from chunk project; dispatch typed alter-chunk-review run event. |
| lib/Controller/API/App/ChangeJobsStatusController.php | Avoid logging raw $_POST. |
| lib/Bootstrap.php | Remove bootstrapCompleted plugin hook invocation. |
| composer.json | Add Gemini client; bump matecat/subfiltering major version. |
| INSTALL/matecat.sql | Make segment_metadata index unique in installer schema. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const handleMouseUp = () => { | ||
| if (!isDraggingRef.current) return | ||
| isDraggingRef.current = false | ||
| setIsDragging(false) | ||
| document.body.style.cursor = '' | ||
| document.body.style.userSelect = '' | ||
| } |
There was a problem hiding this comment.
If the component unmounts while dragging, the cleanup removes listeners but never resets document.body.style.cursor / userSelect, leaving the whole app in row-resize / non-selectable state. In the cleanup function, also set isDraggingRef.current = false, setIsDragging(false) (if needed), and restore the body styles (optionally guarding so you only reset if you set them).
|
|
||
| return () => { | ||
| window.removeEventListener('mousemove', handleMouseMove) | ||
| window.removeEventListener('mouseup', handleMouseUp) |
There was a problem hiding this comment.
If the component unmounts while dragging, the cleanup removes listeners but never resets document.body.style.cursor / userSelect, leaving the whole app in row-resize / non-selectable state. In the cleanup function, also set isDraggingRef.current = false, setIsDragging(false) (if needed), and restore the body styles (optionally guarding so you only reset if you set them).
| window.removeEventListener('mouseup', handleMouseUp) | |
| window.removeEventListener('mouseup', handleMouseUp) | |
| if (isDraggingRef.current) { | |
| isDraggingRef.current = false | |
| setIsDragging(false) | |
| document.body.style.cursor = '' | |
| document.body.style.userSelect = '' | |
| } |
|
|
||
| if(!is_string($metadatum->key) or !is_string($metadatum->value)) { | ||
| $metadatum->value = json_encode($metadatum->value); | ||
| $metadatum->key = json_encode($metadatum->key); | ||
| } | ||
|
|
||
| $this->metadata[] = new AnalysisFileMetadata($metadatum->key, $metadatum->value); |
There was a problem hiding this comment.
The condition uses or, so if either key or value is non-string you JSON-encode both. That corrupts valid string keys (e.g. \"instructions\") when only the value is non-string. Encode/cast key and value independently (e.g., only JSON-encode value when it’s non-scalar) and avoid JSON-encoding keys unless you explicitly support non-string key types.
| if(!is_string($metadatum->key) or !is_string($metadatum->value)) { | |
| $metadatum->value = json_encode($metadatum->value); | |
| $metadatum->key = json_encode($metadatum->key); | |
| } | |
| $this->metadata[] = new AnalysisFileMetadata($metadatum->key, $metadatum->value); | |
| $key = is_string($metadatum->key) ? $metadatum->key : (string)$metadatum->key; | |
| if (is_string($metadatum->value)) { | |
| $value = $metadatum->value; | |
| } elseif (is_scalar($metadatum->value) || $metadatum->value === null) { | |
| $value = (string)$metadatum->value; | |
| } else { | |
| $value = json_encode($metadatum->value); | |
| } | |
| $this->metadata[] = new AnalysisFileMetadata($key, $value); |
| public array $sql_down = [ | ||
| ' | ||
| ALTER TABLE `segment_metadata` REMOVE PARTITIONING; | ||
| ALTER TABLE `segment_metadata` | ||
| DROP INDEX `idx_id_segment_meta_key`, | ||
| ADD INDEX `idx_id_segment_meta_key` (`id_segment`, `meta_key`); | ||
| ' | ||
| ]; |
There was a problem hiding this comment.
The down migration is not a safe inverse of the up migration: REMOVE PARTITIONING is unrelated to the index change and will fail on non-partitioned tables (or change table structure unexpectedly). Also, multiple statements in a single string may not be supported by the migration runner/DB driver. Down should strictly revert the unique index back to a non-unique index (and omit partition operations).
| return $thisDao->setCacheTTL($ttl)->_fetchObjectMap($stmt, OwnerFeatureStruct::class, [ | ||
| 'id_customer' => $id_customer | ||
| ]) ?? []; | ||
| ]); |
There was a problem hiding this comment.
Both methods declare a return type of array, but they now directly return _fetchObjectMap(...) without the previous ?? [] fallback. If _fetchObjectMap can return null (as the old code implied), this will raise a TypeError. Restore the ?? [] fallback or ensure _fetchObjectMap always returns an array (including when there are no results).
| // const rawMetadata = seg.get('metadata') | ||
| // const metadataArr = rawMetadata | ||
| // ? typeof rawMetadata.toJS === 'function' | ||
| // ? rawMetadata.toJS() | ||
| // : rawMetadata | ||
| // : [] | ||
| // const findMeta = (key) => | ||
| // metadataArr.find((m) => m.meta_key === key)?.meta_value ?? null | ||
| // segmentsList.push({ | ||
| // sid: seg.get('sid'), | ||
| // source: seg.get('segment'), | ||
| // target: seg.get('translation'), | ||
| // context_url: seg.get('context_url') ?? null, | ||
| // resname: findMeta('resname'), | ||
| // restype: findMeta('restype'), | ||
| // }) | ||
| // } | ||
| // ContextPreviewChannel.sendMessage({type: 'segments', segments: segmentsList}) | ||
| // }, [segments]) | ||
|
|
There was a problem hiding this comment.
Large commented-out logic in production code makes the intent unclear and is easy to let drift out-of-date. If this is intentionally deferred, prefer removing it and tracking via an issue/PR, or reintroduce it behind a feature flag/config so it stays executable and testable.
| // const rawMetadata = seg.get('metadata') | |
| // const metadataArr = rawMetadata | |
| // ? typeof rawMetadata.toJS === 'function' | |
| // ? rawMetadata.toJS() | |
| // : rawMetadata | |
| // : [] | |
| // const findMeta = (key) => | |
| // metadataArr.find((m) => m.meta_key === key)?.meta_value ?? null | |
| // segmentsList.push({ | |
| // sid: seg.get('sid'), | |
| // source: seg.get('segment'), | |
| // target: seg.get('translation'), | |
| // context_url: seg.get('context_url') ?? null, | |
| // resname: findMeta('resname'), | |
| // restype: findMeta('restype'), | |
| // }) | |
| // } | |
| // ContextPreviewChannel.sendMessage({type: 'segments', segments: segmentsList}) | |
| // }, [segments]) |
| const {placeholderRegex, decodeNeeded, encodedPlaceholder, regex, type} = | ||
| tagSignatures[key] | ||
| const shouldExcludeTag = excludeTags.some((value) => value === type) |
There was a problem hiding this comment.
This changes the destructured property from placeholder to encodedPlaceholder. If tagSignatures[...] entries still provide placeholder (and not encodedPlaceholder), the transform will stop substituting placeholders and will fall back to match. To make this robust, either update the tagSignatures definition consistently or support both keys (e.g., prefer encodedPlaceholder but fallback to placeholder).
| !shouldExcludeTag | ||
| ? (match) => { | ||
| return placeholder ? placeholder : match | ||
| return encodedPlaceholder ? encodedPlaceholder : match |
There was a problem hiding this comment.
This changes the destructured property from placeholder to encodedPlaceholder. If tagSignatures[...] entries still provide placeholder (and not encodedPlaceholder), the transform will stop substituting placeholders and will fall back to match. To make this robust, either update the tagSignatures definition consistently or support both keys (e.g., prefer encodedPlaceholder but fallback to placeholder).
| public function __construct( | ||
| private mixed $segmentsList, | ||
| private readonly array $requestData, | ||
| ) { | ||
| } |
There was a problem hiding this comment.
The event exposes requestData as readonly with only a getter. In the previous hook usage (filter('rewriteContributionContexts', $segmentsList, $request)), plugins could influence both the segments list and the request context. With this design, plugins can only alter segmentsList (via a setter) but cannot update request data at all. If request mutation is still required, add setRequestData(array $requestData): void (and drop readonly) or clarify by removing the unused request reassignment at the call site.
| public function getRequestData(): array | ||
| { | ||
| return $this->requestData; | ||
| } |
There was a problem hiding this comment.
The event exposes requestData as readonly with only a getter. In the previous hook usage (filter('rewriteContributionContexts', $segmentsList, $request)), plugins could influence both the segments list and the request context. With this design, plugins can only alter segmentsList (via a setter) but cannot update request data at all. If request mutation is still required, add setRequestData(array $requestData): void (and drop readonly) or clarify by removing the unused request reassignment at the call site.
No description provided.