Skip to content

Fix namespaces issues#86

Merged
eweren merged 18 commits intotolgee:mainfrom
eweren:fix-namespaces-issues
Jan 19, 2026
Merged

Fix namespaces issues#86
eweren merged 18 commits intotolgee:mainfrom
eweren:fix-namespaces-issues

Conversation

@eweren
Copy link
Collaborator

@eweren eweren commented Dec 17, 2025

Summary by CodeRabbit

  • New Features

    • AutocompleteSelect (single/multi) and Namespace refresh control; hook to detect namespace support.
  • Bug Fixes

    • Hidden-layer filtering now respects hidden ancestors.
    • Faster node deduplication in push flow.
    • Improved push/pull error handling (including image-upload and API key cases).
  • UI/UX Improvements

    • Streamlined namespace selector, tag selector via AutocompleteSelect, z-index and dark-mode refinements.
  • Tests

    • Added push success key-count tests; updated namespace selector tests.
  • Chores

    • API schema generation and client typing adjustments.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 17, 2025

Walkthrough

Refactors namespace UI to AutocompleteSelect, adds namespace-aware hooks/queries, updates push/pull flows to respect namespace settings and improve error handling, adds parent-aware hidden-layer filtering, and introduces multiple UI, style, and type changes across client and tests.

Changes

Cohort / File(s) Summary
Tests
cypress/e2e/index.cy.ts, cypress/e2e/push.cy.ts
Updated namespace selector to general_namespace_select_input, removed a namespace-hide test, and added push tests asserting "Successfully updated 2 key(s)" for new and changed keys.
Scripts
package.json
Updated "schema" script URL to localhost:8085 and changed generated output path to ./src/ui/client/apiSchema.generated.ts.
Core utils & types
src/main/utils/nodeTools.ts, src/main/utils/settingsTools.ts, src/tools/getPushChanges.ts, src/types.ts
nodeTools: run ignoreHiddenLayers block regardless of visibility, add ignoreHiddenLayersIncludingChildren parent traversal with error logging. settingsTools: replace namespacesDisabled with ignoreHiddenLayersIncludingChildren in stored data. getPushChanges: signature now accepts hasNamespacesEnabled and omits ns when namespaces disabled. Types updated accordingly.
API client & typing
src/ui/client/apiSchema.custom.ts, src/ui/client/client.ts, src/ui/client/useQueryApi.ts
Added customPaths for /v2/projects/{projectId} and extended client/useQueryApi generic Paths to include customPaths; URL rewrite now skips when pathParams.projectId is defined.
New component: AutocompleteSelect
src/ui/components/AutocompleteSelect/AutocompleteSelect.tsx, src/ui/components/AutocompleteSelect/AutocompleteSelect.css, src/ui/components/AutocompleteSelect/AutocompleteSelect.css.d.ts
New AutocompleteSelect supporting single/multi modes, keyboard interactions, dropdown placement, CSS and TypeScript typings.
NamespaceSelect refactor
src/ui/components/NamespaceSelect/NamespaceSelect.tsx, .../NamespaceSelect.css, .../NamespaceSelect.css.d.ts
Replaced modal flow with AutocompleteSelect, added onRefresh prop and refresh button with rotating state; aggregates namespaces from API + connected nodes. Props changed (onRefresh added, selectProps removed).
UI / node listing
src/ui/components/NodeList/NodeRow.tsx, src/ui/components/NodeList/NodeRow.css
Label changed from "ns:" to "Namespace:"; CSS tweaks for .ns overflow/text-overflow/margin.
Hooks
src/ui/hooks/useAllTranslations.ts, src/ui/hooks/useHasNamespacesEnabled.ts, src/ui/hooks/useSetNodesDataMutation.ts
useAllTranslations: ref-based caching, isLoading, getData, clearCache, aggregated error. New useHasNamespacesEnabled hook queries API key and project to return useNamespaces. useSetNodesDataMutation invalidates connected nodes on success.
Index / ListItem views
src/ui/views/Index/Index.tsx, src/ui/views/Index/ListItem.tsx, src/ui/views/Index/Index.css, src/ui/views/Index/Index.css.d.ts
Aggregate namespaces from API + connected nodes; pass hasNamespacesEnabled and onRefreshNamespaces into ListItem. ListItem: debounced key updates, removal of editorMode gating, conditional NamespaceSelect rendering by hasNamespacesEnabled. Removed .nsSelect CSS token.
Push flow
src/ui/views/Push/Push.tsx, src/ui/views/Push/Changes.tsx
Integrated hasNamespacesEnabled, O(n) deduplication, namespace-aware diff with cancellation, screenshot upload handling, per-key NEW/OVERRIDE resolution, tagging and big-meta updates, improved error handling, and success counts; UI row height change for New keys.
Pull
src/ui/views/Pull/Pull.tsx
Added specific error handling for "too_many_uploaded_images".
Settings
src/ui/views/Settings/ProjectSettings.tsx, src/ui/views/Settings/PushSection.tsx, src/ui/views/Settings/StringsSection.tsx
ProjectSettings now uses useHasNamespacesEnabled and apiUrl/projectId for help links; PushSection replaced custom tag UI with AutocompleteSelect and tolgeeConfig setters; StringsSection added ignoreHiddenLayersIncludingChildren checkbox and help text. ProjectSettings Props now include apiUrl. PushSection Props updated to accept tolgeeConfig and setTolgeeConfig.
Styles & icons
src/ui/components/ActionsBottom/ActionsBottom.css, src/ui/components/InfoTooltip/InfoTooltip.css, src/ui/icons/SvgIcons.tsx, src/ui/styles.css, src/ui/views/Settings/StringsEditor.css
Increased z-index for ActionsBottom and InfoTooltip, added Refresh SVG (duplicated), added dark-mode text color variable, adjusted placeholder color for dark mode.
Misc UI declarations
src/ui/components/AutocompleteSelect/AutocompleteSelect.css.d.ts, src/ui/components/NamespaceSelect/NamespaceSelect.css.d.ts, src/ui/views/Index/Index.css.d.ts
Added/removed CSS module declaration tokens to match new/removed CSS classes (AutocompleteSelect added tokens; NamespaceSelect added tokens; Index removed nsSelect token).

Sequence Diagram(s)

sequenceDiagram
    participant UI as Push View
    participant Hook as useHasNamespacesEnabled
    participant Query as useQueryApi
    participant API as API Server
    participant Diff as getPushChanges

    UI->>Hook: request hasNamespacesEnabled
    Hook->>Query: GET /v2/api-keys/current
    Query->>API: GET /v2/api-keys/current
    API-->>Query: return apiKey (projectId)
    Query-->>Hook: apiKey/projectId
    Hook->>Query: GET /v2/projects/{projectId}
    Query->>API: GET /v2/projects/{projectId}
    API-->>Query: return project.useNamespaces
    Query-->>Hook: hasNamespacesEnabled
    Hook-->>UI: hasNamespacesEnabled

    UI->>Diff: request translations & screenshots (namespaced if enabled)
    Diff->>Query: fetch translations (conditional namespaces)
    Query-->>Diff: translations
    Diff->>Diff: compute KeyChanges (include ns if enabled)
    Diff-->>UI: KeyChanges

    UI->>UI: deduplicate nodes (O(n))
    UI->>API: upload translations / screenshots / tags
    API-->>UI: responses
    UI->>Query: invalidate getConnectedNodes cache
    UI-->>User: show success with pushed key counts
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • JanCizmar
  • ZuzanaOdstrcilova
  • stepan662

Poem

🐰
I hopped through code to fetch namespaces bright,
Modals became selects—oh what a light!
Push counts sparkle, screenshots take flight,
Hidden parents honored in moonlight,
A carrot-fueled refactor—hop, delight!

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Fix namespaces issues' is vague and generic, using non-descriptive language that doesn't convey specific information about what was actually changed. Use a more specific title that describes the actual changes, such as 'Refactor namespace handling and add ignoreHiddenLayersIncludingChildren setting' or similar.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
cypress/e2e/index.cy.ts (1)

32-53: Test logic is inconsistent after removing namespacesDisabled.

After removing namespacesDisabled: true from the config (line 35), this test now has identical configuration to the first test ({ ...SIGNED_IN }), yet expects opposite behavior:

  • Test 1 (line 8): config: SIGNED_IN → expects namespace selector to exist (lines 25-29)
  • Test 2 (line 35): config: { ...SIGNED_IN } → expects namespace selector to NOT exist (line 52)

Without a config setting to hide the namespace selector, the expectation on line 52 will fail. Please either:

  1. Update the assertion to expect the selector to exist, or
  2. Add a config setting that actually hides the namespace selector, or
  3. Remove this test if it's no longer relevant after the namespace refactor.
🧹 Nitpick comments (5)
src/ui/hooks/useAllTranslations.ts (1)

39-43: Consider simplifying the empty namespace handling logic.

When namespaces is provided (truthy), line 33 assigns nsNames directly from namespaces. This means if namespaces includes "", then nsNames will already include it, making the check on line 41 (!nsNames.includes("")) always true when needed. The defensive code appears correct but may be overly cautious.

Consider this simplification if the intent is to handle only the explicit namespaces parameter case:

-    // Ensure empty string is included if namespaces is provided and contains empty string
-    // This handles the default namespace case
-    if (namespaces && namespaces.includes("") && !nsNames.includes("")) {
-      nsNames.push("");
-    }
+    // Ensure empty string is included when explicitly requested
+    if (namespaces?.includes("") && !nsNames.includes("")) {
+      nsNames.push("");
+    }
src/ui/components/NamespaceSelect/NamespaceSelect.tsx (1)

51-58: Consider simplifying the nested setTimeout pattern.

The double focus() calls with nested timeouts (100ms then 50ms) appear fragile and may not reliably restore focus across different browsers or system loads.

Consider a single timeout with a reasonable delay, or use a more deterministic approach like listening for a state update callback:

       if (wasFocused && inputRef.current) {
-        setTimeout(() => {
-          inputRef.current?.focus();
-          // Small delay to ensure the options are updated
-          setTimeout(() => {
-            inputRef.current?.focus();
-          }, 50);
-        }, 100);
+        // Allow time for options to update before refocusing
+        setTimeout(() => inputRef.current?.focus(), 150);
       }
src/ui/client/useQueryApi.ts (1)

51-65: Consider extending MutationProps with customPaths for consistency.

The useApiQuery hook's Paths generic now includes customPaths (line 32), but MutationProps still defaults to only paths (line 54). If mutations need to support custom endpoints, update line 54 to match:

 export type MutationProps<
   Url extends keyof Paths,
   Method extends keyof Paths[Url],
-  Paths = paths
+  Paths = paths & customPaths
 > = {

If mutations are intentionally restricted to generated paths only, this is acceptable as-is.

src/ui/components/AutocompleteSelect/AutocompleteSelect.tsx (1)

176-191: Consider reducing the blur delay timeout.

The 200ms delay in handleBlur (line 185) allows dropdown item clicks to register before closing, but it also delays the UI response. Consider:

  • Reducing to 100-150ms if 200ms feels sluggish
  • Using onMouseDown for dropdown items (which you already do) to avoid needing such a long delay
src/ui/views/Push/Push.tsx (1)

82-92: Consider including empty namespace in the dependency key.

The requiredNamespacesKey filters out empty/falsy namespaces on line 88, but the actual namespace computation inside the effect (line 127) includes empty strings via node.ns ?? "". While this works because the key is only for dependency tracking, aligning them would make the logic easier to follow.

     const uniqueNamespaces = Array.from(
       new Set(
         deduplicatedNodes
-          .map((node) => node.ns)
-          .filter((ns): ns is string => Boolean(ns))
+          .map((node) => node.ns ?? "")
       )
     );
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aaa074a and d3f8c04.

📒 Files selected for processing (36)
  • cypress/e2e/index.cy.ts (2 hunks)
  • cypress/e2e/push.cy.ts (1 hunks)
  • package.json (1 hunks)
  • src/main/utils/nodeTools.ts (1 hunks)
  • src/main/utils/settingsTools.ts (2 hunks)
  • src/tools/getPushChanges.ts (3 hunks)
  • src/types.ts (1 hunks)
  • src/ui/client/apiSchema.custom.ts (1 hunks)
  • src/ui/client/client.ts (3 hunks)
  • src/ui/client/useQueryApi.ts (2 hunks)
  • src/ui/components/ActionsBottom/ActionsBottom.css (1 hunks)
  • src/ui/components/AutocompleteSelect/AutocompleteSelect.css (1 hunks)
  • src/ui/components/AutocompleteSelect/AutocompleteSelect.css.d.ts (1 hunks)
  • src/ui/components/AutocompleteSelect/AutocompleteSelect.tsx (1 hunks)
  • src/ui/components/InfoTooltip/InfoTooltip.css (1 hunks)
  • src/ui/components/NamespaceSelect/NamespaceSelect.css (1 hunks)
  • src/ui/components/NamespaceSelect/NamespaceSelect.css.d.ts (1 hunks)
  • src/ui/components/NamespaceSelect/NamespaceSelect.tsx (1 hunks)
  • src/ui/components/NodeList/NodeRow.css (1 hunks)
  • src/ui/components/NodeList/NodeRow.tsx (1 hunks)
  • src/ui/hooks/useAllTranslations.ts (2 hunks)
  • src/ui/hooks/useHasNamespacesEnabled.ts (1 hunks)
  • src/ui/hooks/useSetNodesDataMutation.ts (1 hunks)
  • src/ui/icons/SvgIcons.tsx (1 hunks)
  • src/ui/styles.css (1 hunks)
  • src/ui/views/Index/Index.css (0 hunks)
  • src/ui/views/Index/Index.css.d.ts (0 hunks)
  • src/ui/views/Index/Index.tsx (4 hunks)
  • src/ui/views/Index/ListItem.tsx (3 hunks)
  • src/ui/views/Pull/Pull.tsx (1 hunks)
  • src/ui/views/Push/Push.tsx (10 hunks)
  • src/ui/views/Settings/ProjectSettings.tsx (6 hunks)
  • src/ui/views/Settings/PushSection.tsx (3 hunks)
  • src/ui/views/Settings/Settings.tsx (1 hunks)
  • src/ui/views/Settings/StringsEditor.css (1 hunks)
  • src/ui/views/Settings/StringsSection.tsx (4 hunks)
💤 Files with no reviewable changes (2)
  • src/ui/views/Index/Index.css.d.ts
  • src/ui/views/Index/Index.css
🧰 Additional context used
🧬 Code graph analysis (14)
src/ui/hooks/useSetNodesDataMutation.ts (3)
src/main/endpoints/setNodesData.ts (2)
  • SetNodesDataProps (5-7)
  • setNodesDataEndpoint (9-28)
src/main/utils/delayed.ts (1)
  • delayed (1-6)
src/main/endpoints/getConnectedNodes.ts (1)
  • getConnectedNodesEndpoint (9-22)
cypress/e2e/push.cy.ts (2)
src/web/urlConfig.ts (2)
  • createTestNode (82-93)
  • SIGNED_IN (39-45)
cypress/common/tools.ts (1)
  • visitWithState (5-9)
src/ui/hooks/useHasNamespacesEnabled.ts (1)
src/ui/client/useQueryApi.ts (1)
  • useApiQuery (29-49)
cypress/e2e/index.cy.ts (2)
src/web/urlConfig.ts (2)
  • createTestNode (82-93)
  • SIGNED_IN (39-45)
cypress/common/tools.ts (1)
  • visitWithState (5-9)
src/ui/client/useQueryApi.ts (2)
src/ui/client/apiSchema.generated.ts (1)
  • paths (7-895)
src/ui/client/apiSchema.custom.ts (1)
  • customPaths (6-14)
src/ui/views/Settings/StringsSection.tsx (1)
src/ui/components/InfoTooltip/InfoTooltip.tsx (1)
  • InfoTooltip (15-33)
src/ui/views/Index/ListItem.tsx (1)
src/ui/components/NamespaceSelect/NamespaceSelect.tsx (1)
  • NamespaceSelect (15-96)
src/ui/views/Settings/PushSection.tsx (1)
src/ui/components/AutocompleteSelect/AutocompleteSelect.tsx (1)
  • AutocompleteSelect (39-327)
src/ui/client/apiSchema.custom.ts (1)
src/ui/client/apiSchema.generated.ts (2)
  • operations (3321-11264)
  • components (899-3315)
src/ui/views/Push/Push.tsx (5)
src/tools/getPushChanges.ts (2)
  • KeyChanges (17-22)
  • getPushChanges (24-105)
src/types.ts (1)
  • NodeInfo (74-86)
src/ui/hooks/useAllTranslations.ts (1)
  • useAllTranslations (12-108)
src/ui/hooks/useHasNamespacesEnabled.ts (1)
  • useHasNamespacesEnabled (3-35)
src/main/endpoints/getScreenshots.ts (1)
  • getScreenshotsEndpoint (9-54)
src/ui/views/Index/Index.tsx (2)
src/ui/hooks/useHasNamespacesEnabled.ts (1)
  • useHasNamespacesEnabled (3-35)
src/ui/hooks/useConnectedNodes.ts (1)
  • useConnectedNodes (8-16)
src/tools/getPushChanges.ts (1)
src/tools/compareNs.ts (1)
  • compareNs (1-3)
src/ui/views/Settings/ProjectSettings.tsx (3)
src/ui/hooks/useHasNamespacesEnabled.ts (1)
  • useHasNamespacesEnabled (3-35)
src/ui/components/InfoTooltip/InfoTooltip.tsx (1)
  • InfoTooltip (15-33)
src/ui/client/decodeApiKey.ts (1)
  • getProjectIdFromApiKey (57-74)
src/ui/client/client.ts (2)
src/ui/client/apiSchema.generated.ts (1)
  • paths (7-895)
src/ui/client/apiSchema.custom.ts (1)
  • customPaths (6-14)
🪛 GitHub Check: Static check 🪲
src/ui/views/Settings/Settings.tsx

[warning] 23-23:
'getProjectIdFromApiKey' is defined but never used


[warning] 15-15:
'useApiQuery' is defined but never used

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Cypress
🔇 Additional comments (52)
src/ui/views/Pull/Pull.tsx (1)

56-59: LGTM! Clear error handling for image upload limits.

The error handling logic is correct and the error message provides clear, actionable guidance to users.

src/ui/styles.css (1)

39-39: LGTM!

The addition of the dark mode text color variable is appropriate. White text (#ffffff) provides good contrast on dark backgrounds.

src/ui/views/Settings/StringsEditor.css (1)

162-166: LGTM!

The dark mode override for placeholder text improves readability. Using --figma-color-text-primary (white) instead of grey text provides better contrast on dark backgrounds.

cypress/e2e/index.cy.ts (1)

25-29: LGTM! Selector and assertion correctly updated.

The migration from a select dropdown to an input-based namespace selector is properly reflected here. The functional expectation checking for an empty value is appropriate.

src/ui/components/ActionsBottom/ActionsBottom.css (1)

10-10: LGTM! Z-index adjustment aligns with UI layering updates.

The z-index increase from 1 to 2 ensures proper stacking with other overlay components introduced in this PR.

src/ui/components/InfoTooltip/InfoTooltip.css (1)

6-6: LGTM! Z-index addition ensures proper tooltip layering.

The added z-index coordinates with other UI stacking adjustments across the PR.

src/ui/hooks/useSetNodesDataMutation.ts (1)

9-20: LGTM! Query invalidation pattern ensures data freshness.

The onSuccess handler properly invalidates the connected nodes query after mutation succeeds, ensuring the UI displays up-to-date data.

src/ui/components/NodeList/NodeRow.tsx (1)

88-88: LGTM! Improved label clarity.

Changing "ns:" to "Namespace:" makes the UI more user-friendly and explicit.

src/types.ts (1)

118-118: LGTM! Settings type extension for hidden layer handling.

The new ignoreHiddenLayersIncludingChildren property appropriately extends the GlobalSettings type for parent-chain visibility checks.

src/ui/components/NodeList/NodeRow.css (1)

41-43: LGTM! CSS changes support improved namespace display.

The overflow and text-overflow adjustments allow the full namespace text to be visible, complementing the "Namespace:" label change.

package.json (1)

9-9: LGTM! Schema generation script updated for new API structure.

The updated endpoint URL and output path align with the UI-centric API schema organization introduced in this PR.

src/ui/hooks/useAllTranslations.ts (1)

101-103: LGTM!

The clearCache() method provides a clean way to reset translations data, which aligns with the broader namespace refresh functionality introduced in this PR.

src/ui/components/NamespaceSelect/NamespaceSelect.css (1)

11-63: LGTM!

The styling for the NamespaceSelect component is well-structured with:

  • Proper positioning and layout for the input wrapper and refresh button
  • Clear interaction states (hover, disabled)
  • Smooth rotation animation for the refresh action
src/main/utils/settingsTools.ts (1)

76-76: LGTM!

The new ignoreHiddenLayersIncludingChildren setting is properly integrated into the plugin data flow, being destructured from input and persisted to document settings. This aligns with the PR's objective to refine hidden layer detection logic.

Also applies to: 95-95

src/ui/icons/SvgIcons.tsx (1)

187-201: LGTM!

The new Refresh icon component follows the established pattern of other icon components in this file, using currentColor for flexible theming and spreading props for maximum reusability.

src/ui/views/Index/Index.tsx (3)

67-87: LGTM!

The allAvailableNamespaces computation efficiently combines API and node-based namespaces with proper deduplication and sorting. The sorting logic correctly places empty string at the end while maintaining alphabetical order for other namespaces.


90-92: LGTM!

The handleRefreshNamespaces function properly refreshes both the API namespaces and connected nodes data sources using Promise.all, ensuring the UI stays in sync with the latest namespace state.


241-246: LGTM!

The updated ListItem props correctly wire up the namespace enablement flag, dynamically computed namespace list, and refresh callback, enabling the component to conditionally render namespace selection UI and trigger refreshes when needed.

cypress/e2e/push.cy.ts (2)

82-115: LGTM!

The test properly verifies that pushing new keys displays the correct count in the success message. The test flow is clear: setup test data → verify diff display → submit push → assert success count.


117-150: LGTM!

The test properly verifies that pushing changed keys displays the correct count in the success message, following the same reliable pattern as the new keys test.

src/ui/components/AutocompleteSelect/AutocompleteSelect.css (1)

1-61: LGTM!

The AutocompleteSelect styling is well-structured with:

  • Proper positioning variants for dropdown direction (up/down)
  • Clear visual hierarchy with headers and items
  • Appropriate interaction states (hover, cursor)
  • Themed colors using Figma CSS variables
src/tools/getPushChanges.ts (3)

38-50: LGTM on conditional namespace comparison.

The logic correctly skips namespace comparison when hasNamespacesEnabled is false, using short-circuit evaluation with compareNs.


85-93: LGTM on KeyChangeValue construction.

Setting ns to undefined when namespaces are disabled ensures consistent downstream handling.


24-30: LGTM on the function signature change.

The parameter change to hasNamespacesEnabled correctly controls namespace behavior in the push logic. The implementation properly guards namespace comparisons (line 42) and conditionally sets the ns field (line 87). All callers have been updated—the single caller in Push.tsx correctly passes the new parameter.

src/main/utils/nodeTools.ts (1)

34-59: LGTM on the hidden layer visibility logic.

The refactored logic correctly:

  1. Checks node's own visibility first
  2. Optionally traverses the parent chain when ignoreHiddenLayersIncludingChildren is enabled
  3. Uses defensive programming with try-catch around parent traversal

One consideration: the catch block logs the error but allows the function to continue (potentially returning true). This is a reasonable fallback—if we can't determine parent visibility, we include the node rather than silently exclude it.

src/ui/client/client.ts (1)

124-127: LGTM on the extended Paths type.

The intersection paths & customPaths correctly extends the API client to support both generated and custom endpoint definitions.

src/ui/components/AutocompleteSelect/AutocompleteSelect.css.d.ts (1)

1-12: LGTM!

Standard CSS module type declaration file with correct readonly properties and CommonJS-style export.

src/ui/components/NamespaceSelect/NamespaceSelect.tsx (1)

65-95: LGTM on the component structure.

The integration with AutocompleteSelect and conditional refresh button rendering is clean. The isRefreshing state correctly disables the button and applies the rotating animation.

src/ui/components/NamespaceSelect/NamespaceSelect.css.d.ts (1)

1-12: LGTM!

The CSS type definitions correctly expose the new class names needed for the enhanced NamespaceSelect UI (container, refresh button, animations, etc.).

src/ui/views/Settings/StringsSection.tsx (3)

82-98: LGTM!

The help text clearly explains the behavior of the "Including all child texts" option and how it differs from the basic hidden layers setting.


139-142: LGTM!

State management for ignoreHiddenLayersIncludingChildren follows the existing patterns consistently, with proper initialization from config and handler to update both local state and config.

Also applies to: 203-211


308-329: LGTM!

The UI properly implements the nested checkbox pattern with appropriate indentation and conditional rendering. The InfoTooltip provides helpful context for users.

src/ui/views/Index/ListItem.tsx (3)

17-29: LGTM!

The props interface correctly extends to support namespace enablement detection and refresh behavior. The function signature properly destructures the new props.


101-111: LGTM!

The NamespaceSelect rendering is now properly gated by hasNamespacesEnabled and the onRefresh callback is correctly passed through for refresh functionality.


125-136: LGTM!

The simplified InsertLink rendering based on node.connected is cleaner and maintains the same visual behavior (secondary color for unconnected state).

src/ui/views/Settings/ProjectSettings.tsx (2)

136-142: LGTM!

The namespace sorting logic correctly places empty strings at the end while maintaining alphabetical order for named namespaces.


20-77: LGTM!

The dynamic help text functions properly generate project-specific documentation links. The dual functions (namespaceHelpText and namespaceHelpTextSetUp) provide appropriate guidance for both enabled and disabled namespace states.

src/ui/client/apiSchema.custom.ts (1)

1-68: LGTM!

The custom API schema is well-structured and follows the same patterns as the generated schema. It properly:

  • References existing components["schemas"] types for consistency
  • Includes comprehensive response types for success and error cases
  • Provides clear documentation comments
  • Types the projectId parameter correctly as a number
src/ui/views/Settings/PushSection.tsx (2)

25-30: LGTM!

The tag options are efficiently computed with useMemo and properly sorted alphabetically for a better user experience.


88-97: LGTM!

The AutocompleteSelect integration simplifies the tag management UI significantly. The configuration is appropriate with multi-select mode enabled and descriptive placeholders for existing and new tags.

src/ui/components/AutocompleteSelect/AutocompleteSelect.tsx (5)

13-37: LGTM!

The discriminated union for Props correctly types single-select vs multi-select modes, ensuring type safety for value and onChange at compile time.


73-99: LGTM!

The display logic and sync effect correctly handle the single-select mode behavior:

  • Shows the selected value when not focused
  • Shows the input value when focused
  • Syncs back to the selected value when focus is lost

101-129: LGTM!

The filtering and validation logic correctly:

  • Filters options based on input
  • Excludes selected values in multi-select mode
  • Detects exact matches
  • Prevents duplicate additions

130-166: LGTM!

Event handlers properly manage both single-select and multi-select flows with appropriate type guards and state updates.


193-326: LGTM!

The rendering logic is comprehensive:

  • Displays badges for multi-select values with remove functionality
  • Provides accessible input with proper ARIA attributes
  • Renders dropdown with dynamic positioning
  • Highlights matching text segments
  • Shows "Add" option for new values
  • Handles empty states appropriately
src/ui/views/Push/Push.tsx (7)

44-50: LGTM!

The new state variables (isPushing, pushedKeysCount, screenshotCount) appropriately support the enhanced push progress tracking and success screen functionality.


56-68: Good performance optimization.

The O(n²) to O(n) deduplication improvement using a Set is a solid change. The composite key correctly handles both key and namespace for uniqueness.


111-145: Well-structured effect with proper cancellation handling.

The cancellation pattern using a cancelled flag correctly prevents state updates after unmount or dependency changes. The early return when success is true is a good optimization. The use of primitive keys as dependencies to avoid object reference issues is a valid pattern.


352-379: Good resilience pattern for non-critical operations.

Wrapping tag addition in a separate try-catch allows the push to succeed even if tagging fails. The error message correctly indicates that translations were still updated.


412-419: Cache invalidation correctly preserves pushed count.

Storing keysPushed before clearing cache ensures the success screen displays accurate counts. The cache clear prevents stale translation data on subsequent operations.


474-488: Clean success screen implementation.

The success UI correctly uses preserved counts and provides clear feedback to the user with the option to return to the main view.


489-490: LGTM!

Including isPushing in the loading condition correctly shows the loading state during the push operation.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/ui/views/Push/Push.tsx (1)

82-92: Consider extracting namespace computation to avoid duplication.

This namespace extraction logic is duplicated in the useEffect (lines 125-129). While both implementations are correct, extracting it to a memoized value would improve maintainability.

Consider refactoring:

-  const requiredNamespacesKey = useMemo(() => {
-    if (!hasNamespacesEnabled) return "";
-    const uniqueNamespaces = Array.from(
-      new Set(
-        deduplicatedNodes
-          .map((node) => node.ns)
-          .filter((ns): ns is string => Boolean(ns))
-      )
-    );
-    return uniqueNamespaces.sort().join(",");
-  }, [deduplicatedNodes, hasNamespacesEnabled]);
+  const requiredNamespaces = useMemo(() => {
+    if (!hasNamespacesEnabled || deduplicatedNodes.length === 0) return undefined;
+    return Array.from(
+      new Set(deduplicatedNodes.map((node) => node.ns ?? ""))
+    );
+  }, [deduplicatedNodes, hasNamespacesEnabled]);
+
+  const requiredNamespacesKey = useMemo(() => {
+    return requiredNamespaces ? requiredNamespaces.slice().sort().join(",") : "";
+  }, [requiredNamespaces]);

Then use requiredNamespaces directly in the useEffect instead of recomputing it at lines 124-129.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d3f8c04 and b95adad.

📒 Files selected for processing (1)
  • src/ui/views/Push/Push.tsx (10 hunks)
🔇 Additional comments (6)
src/ui/views/Push/Push.tsx (6)

56-68: LGTM! Efficient deduplication optimization.

The Set-based approach correctly reduces complexity from O(n²) to O(n), and the composite key properly accounts for namespace differentiation.


111-193: LGTM! Well-implemented diff computation with cancellation.

The centralized useEffect correctly handles async operations with proper cancellation to prevent stale state updates. The comprehensive dependency array ensures recomputation when relevant inputs change, and the early return when success is true avoids unnecessary work.


398-398: LGTM! Stale closure issue resolved.

The functional updater setUploadedScreenshotCount((c) => c + 1) correctly addresses the stale closure bug mentioned in past review comments. This ensures the count increments properly across async iterations.


413-422: LGTM! Proper state management and cache invalidation.

Storing the pushed keys count before clearing the cache and connecting nodes ensures accurate UI display, and clearing the translations cache ensures newly pushed keys are recognized on subsequent operations.


475-489: LGTM! Clear success feedback with accurate counts.

The success screen provides immediate feedback using the stored pushedKeysCount and uploadedScreenshotCount, avoiding the need to wait for diff recomputation. The conditional display based on uploadScreenshots appropriately reflects the user's choice.


266-268: The ArrayBuffer cast is correct and safe.

screenshot.image is typed as Uint8Array (not Node.js Buffer), and accessing .buffer on a Uint8Array returns the underlying ArrayBuffer. The cast is redundant but harmless—the Blob constructor accepts both ArrayBuffer and typed arrays like Uint8Array directly.

Likely an incorrect or invalid review comment.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/ui/views/Push/Push.tsx (1)

443-448: Reset uploadedScreenshotCount in handleRepeat.

Similar to the past review comment about screenshot count, if a push partially completes (some screenshots uploaded) before failing, uploadedScreenshotCount retains its value. On retry, the count will be incorrect since it starts from the previous partial value instead of zero.

Apply this diff to reset the screenshot count:

 const handleRepeat = () => {
   setError(false);
   setSuccess(false);
   setPushedKeysCount(0);
+  setUploadedScreenshotCount(0);
   setErrorMessage(undefined);
 };
🧹 Nitpick comments (1)
src/ui/views/Push/Push.tsx (1)

320-332: Optional: Simplify resolution for changedKeys.

Since changedKeys always have oldValue (by definition from getPushChanges), the conditional on line 328 will always evaluate to "OVERRIDE". Consider simplifying:

         translations: {
           [language]: {
             text: item.newValue,
-            resolution: item.oldValue ? "OVERRIDE" : "NEW",
+            resolution: "OVERRIDE",
           },
         },

This is defensive programming and not a bug, but simplification improves clarity.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b95adad and 30152a1.

📒 Files selected for processing (3)
  • cypress/e2e/index.cy.ts (1 hunks)
  • cypress/e2e/push.cy.ts (2 hunks)
  • src/ui/views/Push/Push.tsx (10 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/ui/views/Push/Push.tsx (5)
src/tools/getPushChanges.ts (2)
  • KeyChanges (17-22)
  • getPushChanges (24-105)
src/ui/hooks/useConnectedNodes.ts (1)
  • useConnectedNodes (8-16)
src/types.ts (1)
  • NodeInfo (74-86)
src/ui/hooks/useHasNamespacesEnabled.ts (1)
  • useHasNamespacesEnabled (3-35)
src/main/endpoints/getScreenshots.ts (1)
  • getScreenshotsEndpoint (9-54)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Cypress
🔇 Additional comments (18)
cypress/e2e/push.cy.ts (3)

82-115: LGTM! Well-structured test for new keys.

The test follows existing patterns, includes clear comments, and appropriately verifies that the success message displays the correct count of pushed keys.


117-150: LGTM! Well-structured test for changed keys.

The test follows existing patterns, includes clear comments, and appropriately verifies that the success message displays the correct count of pushed keys.


154-154: Verify test independence.

The text change from "On the road" to "Changed text 2" aligns with the new test at line 120 that uses the same key. However, Cypress tests should be isolated and independent. Please confirm that:

  1. Tests don't share state or depend on execution order
  2. This change is for clarity/consistency rather than to fix test interdependence

If these tests are truly independent (as they should be), the original text "On the road" should work just as well as "Changed text 2".

Also applies to: 164-164

cypress/e2e/index.cy.ts (2)

25-29: LGTM! Selector and assertion updated correctly for AutocompleteSelect.

The change from a select dropdown to general_namespace_select_input and the functional assertion with the || "" fallback appropriately handle the new AutocompleteSelect component behavior, where the value might be null or undefined.


54-54: The selectors in lines 54 and 84-87 are correct and should not be changed. general_node_list_row_namespace targets a read-only display element in the NodeRow component for connected nodes, while general_namespace_select_input targets an editable AutocompleteSelect input in the NamespaceSelect component for unconnected nodes. These serve different UI purposes and intentionally use different selectors.

src/ui/views/Push/Push.tsx (13)

32-32: LGTM! Namespace detection and progress tracking state additions.

The new state variables (isPushing, pushedKeysCount, uploadedScreenshotCount) and the useHasNamespacesEnabled hook properly support the namespace-aware push flow and progress tracking requirements.

Also applies to: 44-44, 47-47, 50-50, 71-71


56-68: Excellent performance optimization!

The deduplication logic correctly reduces time complexity from O(n²) to O(n) using a Set, and properly includes namespace in the composite key to avoid conflating identically named keys from different namespaces.


73-110: Well-designed memoization strategy.

The memoized keys (nodesKey, requiredNamespacesKey, screenshotsKey) and extracted primitives from tolgeeConfig effectively stabilize the useEffect dependencies, preventing unnecessary recomputations while capturing all relevant changes including namespace updates.


111-193: Robust async effect with proper cancellation.

The refactored diff computation properly handles:

  • Namespace-aware translation loading
  • Cancellation to prevent race conditions
  • Comprehensive error handling with specific messages for invalid API keys
  • Stable dependencies via memoized keys

The effect safely uses deduplicatedNodes without including it in the deps array because changes to nodes are captured by nodesKey.


195-197: LGTM! Appropriate memoization.

The totalScreenshotCount is correctly memoized from the changes state and used consistently throughout the UI.


255-256: LGTM! Proper counter initialization.

The counters are correctly reset before starting the push operation.


266-268: LGTM! Correct ArrayBuffer cast.

The cast of screenshot.image.buffer as ArrayBuffer is correct; Uint8Array.buffer returns an ArrayBuffer, which is the proper type for Blob construction.


353-411: Excellent error handling with partial success support.

The granular error handling allows the push to succeed even if tag application or screenshot updates fail, with clear user-facing messages. Line 398 correctly uses a functional state updater setUploadedScreenshotCount((c) => c + 1) to avoid stale closure bugs in the async loop.


413-420: LGTM! Proper cache management.

The key count is correctly stored before clearing the translation cache, ensuring the success screen displays accurate counts while the cache is refreshed for subsequent operations.


423-436: LGTM! Comprehensive error handling.

The enhanced error messages provide specific, actionable feedback for common failure scenarios including invalid API keys, too many images, and import errors.


456-460: LGTM! Correct changesSize computation.

Using pushedKeysCount when displaying the success state ensures the UI shows the actual number of keys that were pushed, regardless of any subsequent diff recomputations.


475-489: LGTM! Improved success screen UX.

The immediate success screen provides clear feedback with accurate counts, and the success state in the useEffect dependencies (line 192) correctly prevents unnecessary recomputation while showing the success message.


490-490: LGTM! Consistent UI updates.

The UI consistently uses totalScreenshotCount and properly includes isPushing in the loading condition, ensuring accurate progress display throughout the push flow.

Also applies to: 507-520, 531-532

@eweren
Copy link
Collaborator Author

eweren commented Jan 2, 2026

@JanCizmar please merge this, if it's fine :)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/ui/views/Push/Push.tsx (2)

147-152: Consider simplifying config reconstruction.

The configForDiff object spreads tolgeeConfig and then re-assigns the same fields that are already present. You can pass tolgeeConfig directly to getPushChanges or only override fields that differ from the source.

🔎 Simplified approach
-        // Reconstruct tolgeeConfig object for getPushChanges
-        const configForDiff = {
-          ...tolgeeConfig,
-          tags: tolgeeConfig?.tags,
-          updateScreenshots: tolgeeConfigUpdateScreenshots,
-          addTags: tolgeeConfigAddTags,
-        };
-
         setChanges(
           getPushChanges(
             deduplicatedNodes,
             translations,
             hasNamespacesEnabled,
             screenshots,
-            configForDiff
+            tolgeeConfig
           )
         );

382-411: Functional state updater correctly prevents stale closure.

Line 398 correctly uses setUploadedScreenshotCount((c) => c + 1) to avoid the stale closure bug flagged in previous reviews. The individual try-catch blocks enable partial success when updating screenshots.

Minor improvement: If multiple screenshots fail, only the last error message is preserved. Consider accumulating errors or showing a count of failures for better UX.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 30152a1 and 39a33d2.

📒 Files selected for processing (3)
  • src/ui/client/client.ts
  • src/ui/hooks/useHasNamespacesEnabled.ts
  • src/ui/views/Push/Push.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/ui/hooks/useHasNamespacesEnabled.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Cypress
🔇 Additional comments (18)
src/ui/client/client.ts (3)

6-6: LGTM: Custom paths import added.

The import of customPaths is used appropriately to extend the API path definitions.


140-146: Critical issue from past review has been fixed!

The unreachable condition issue has been correctly resolved. The code now checks if pathParams.projectId is undefined (line 142) before assigning to it (line 145), making the conditional logic for URL rewriting work as intended.

The current flow is correct:

  1. Extract projectId from API key
  2. If projectId exists and wasn't already provided in pathParams, add the placeholder to the URL
  3. Assign projectId to pathParams for placeholder replacement

Note: Line 145 will overwrite any explicit pathParams.projectId with the value from the API key, which appears intentional as the API key is the source of truth.


127-127: No type conflicts found.

The intersection type paths & customPaths is safe. The customPaths interface adds the single endpoint "/v2/projects/{projectId}" which does not exist in the generated paths, so there are no overlapping keys and no type conflicts.

src/ui/views/Push/Push.tsx (15)

56-68: LGTM! Excellent deduplication optimization.

The refactoring from O(n²) to O(n) using a Set is a solid performance improvement. The composite key properly accounts for both key and namespace.


71-71: Good addition for namespace-aware logic.

The useHasNamespacesEnabled hook integrates well with the namespace-aware refactoring mentioned in the PR objectives.


74-109: Excellent memoization strategy.

The stable keys (nodesKey, requiredNamespacesKey, screenshotsKey) and extracted primitive values from tolgeeConfig are well-designed optimizations that prevent unnecessary recomputation while maintaining correctness.


195-197: LGTM!

The memoized totalScreenshotCount is a good optimization for UI consistency.


255-257: LGTM!

Proper initialization of push state counters before starting the push operation.


328-328: LGTM!

The conditional resolution logic correctly distinguishes between overriding existing translations and creating new ones based on the presence of oldValue.


353-380: Good partial-success error handling.

The try-catch around tagging allows the push to succeed even if tagging fails, with a clear message to the user. This graceful degradation improves UX when non-critical operations fail.


414-420: LGTM! Proper cache invalidation.

Storing the pushed key count before clearing the cache and then calling clearCache() ensures newly pushed keys will be recognized in subsequent operations.


427-435: LGTM! Enhanced error handling.

The specific error cases for too_many_uploaded_images and import_keys_error provide better user feedback than generic error messages.


443-449: LGTM! Past review feedback addressed.

The reset logic now correctly includes both setPushedKeysCount(0) and setUploadedScreenshotCount(0), addressing the issues flagged in previous reviews about incomplete state resets on retry.


476-490: LGTM! Improved success screen UX.

The success screen displays immediately after push completion with clear metrics (pushed keys count and uploaded screenshots count), providing good user feedback without waiting for data recomputation.


491-491: LGTM!

Adding isPushing to the loading condition correctly prevents user interaction during the push operation.


508-521: LGTM!

Consistent use of totalScreenshotCount throughout the UI improves code clarity and maintainability.


532-544: LGTM!

The finish button logic correctly handles the case where there are no changes and either no screenshots or screenshots are not being uploaded.


266-268: The type system already guarantees that screenshot.image.buffer is an ArrayBuffer since screenshot.image is typed as Uint8Array. The cast is redundant but does not cause issues.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/ui/views/Index/ListItem.tsx (2)

84-99: Double mutation on namespace change.

When namespace changes, two mutations are triggered:

  1. The useEffect at lines 84-90 fires when namespace changes
  2. handleNsChange at lines 94-96 also calls setNodesDataMutation.mutate

This causes redundant API calls. Since handleNsChange already performs the mutation, the useEffect dependency on namespace creates a duplicate.

🐛 Proposed fix: Remove the namespace useEffect
-  useEffect(() => {
-    if (keyName && namespace !== node.ns) {
-      setNodesDataMutation.mutate({
-        nodes: [{ ...node, key: keyName, ns: namespace }],
-      });
-    }
-  }, [namespace]);
-
   const handleNsChange = (node: NodeInfo) => (value: string) => {
     setNamespace(value);
     setNodesDataMutation.mutate({
       nodes: [{ ...node, key: keyName, ns: value }],
     });
-    node.key = keyName;
-    node.ns = value;
   };

97-98: Avoid direct mutation of props.

Mutating node.key and node.ns directly modifies the prop object, which is a React anti-pattern. This can cause unpredictable behavior since the parent component doesn't expect its data to be mutated. The mutation call should be sufficient to update the Figma nodes.

🐛 Proposed fix
   const handleNsChange = (node: NodeInfo) => (value: string) => {
     setNamespace(value);
     setNodesDataMutation.mutate({
       nodes: [{ ...node, key: keyName, ns: value }],
     });
-    node.key = keyName;
-    node.ns = value;
   };
🤖 Fix all issues with AI agents
In `@src/ui/hooks/useAllTranslations.ts`:
- Line 117: The error aggregation uses the wrong loadable: change the error
source from translationsLoadable.error to translationsBaseLoadable.error so
translation fetch failures are captured; update the code that computes the error
(where const error = namespacesLoadable.error || translationsLoadable.error) to
reference translationsBaseLoadable.error, ensuring this aligns with the loadData
implementation that calls translationsBaseLoadable.
🧹 Nitpick comments (2)
src/ui/hooks/useAllTranslations.ts (1)

17-20: Remove unused translationsLoadable mutation.

This mutation is defined but never invoked anywhere in the hook. Only translationsBaseLoadable is used for fetching translations. Consider removing this dead code.

♻️ Proposed removal
-  const translationsLoadable = useApiMutation({
-    url: "/v2/projects/translations/{languages}",
-    method: "get",
-  });

Also update the error aggregation accordingly (see related comment).

src/ui/views/Index/ListItem.tsx (1)

80-82: Simplify handleKeyChange - unnecessary currying.

handleKeyChange returns a function but the outer function takes no parameters, making the currying pattern unnecessary. This appears to be leftover from when it may have accepted a node parameter.

♻️ Proposed simplification
-  const handleKeyChange = () => (value: string) => {
+  const handleKeyChange = (value: string) => {
     setKeyName(value);
   };

And update the usage:

-          <KeyInput value={keyName || ""} onChange={handleKeyChange()} />
+          <KeyInput value={keyName || ""} onChange={handleKeyChange} />

Also applies to: 106-106

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/ui/hooks/useAllTranslations.ts`:
- Around line 48-52: In useAllTranslations.ts the conditional block checking "if
(namespaces && namespaces.includes(\"\") && !nsNames.includes(\"\")) {
nsNames.push(\"\"); }" is dead code because nsNames is assigned from namespaces
earlier, so the second check can never be true; remove this unreachable
conditional entirely (delete the block referencing namespaces and nsNames) to
clean up logic and avoid confusion.

@eweren eweren merged commit 0d6b902 into tolgee:main Jan 19, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants