feat(team-library): share connections and saved queries with your team#1832
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4883c67d9a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| } | ||
|
|
||
| func pullIfNeeded() async { | ||
| guard isFeatureAvailable(), TeamLibraryMetadataStorage.isPullDue else { return } |
There was a problem hiding this comment.
Scope the team-library cache to the active license
After a successful pull, lastPullAt is global and start() loads the single team_library.json cache before this guard. If someone deactivates Team A and activates/joins Team B on the same Mac within seven days, isFeatureAvailable() is true but this guard skips the network pull, so the UI continues exposing Team A’s cached queries/connections under Team B. Key the cache and pull timestamp by license/team, or clear/pull whenever the active license changes.
Useful? React with 👍 / 👎.
| AnalyticsService.shared.startPeriodicHeartbeat() | ||
| SyncCoordinator.shared.start() | ||
| LinkedFolderWatcher.shared.start() | ||
| TeamLibrarySyncCoordinator.shared.start() |
There was a problem hiding this comment.
Trigger team-library sync after activation
Starting the coordinator only from post-launch activation means a common flow is missed: when the app launches unlicensed or on Starter, start() returns at its feature gate, and activating a Team license or accepting an invite later does not call start() or pull(). Since periodic validation only runs on the 7-day cadence, newly joined Team users will not see shared queries until relaunch or revalidation; trigger a pull from the activation/status-change path as well.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c66570cf20
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let placeholderURL = URL(fileURLWithPath: "/") | ||
| return TeamLibrarySyncCoordinator.shared.library.connections.map { connection in | ||
| LinkedConnection( | ||
| id: UUID(uuidString: connection.sourceConnectionId ?? "") ?? UUID(), |
There was a problem hiding this comment.
Use a distinct ID for team-library rows
When a user has already published one of their local connections, sourceConnectionId is that local connection UUID, so using it as the LinkedConnection.id gives the Team Library row the same List tag as the local row. Selecting or double-clicking that Team Library row then makes primaryAction match both the local-connection loop and the team-library loop, opening both copies and resolving context menus as the local connection. Use a team-library-specific stable ID, such as the server connection.id, instead of the source local ID.
Useful? React with 👍 / 👎.
| vm.connectToLinkedConnection(linked) | ||
| } | ||
| for linked in vm.teamLibraryConnections where ids.contains(linked.id) { | ||
| vm.connectToLinkedConnection(linked) |
There was a problem hiding this comment.
Preserve the full shared connection payload
When a shared Team Library connection uses SSH/SSL settings, Redis DB, startup commands, or plugin additional fields, routing it through connectToLinkedConnection drops those fields because that helper reconstructs a DatabaseConnection from only id/name/host/port/database/username/type before opening it. The pulled ExportableConnection already contains the remaining payload, so Team Library connections that need those settings will fail or connect incorrectly; this path should import/convert the full exportable payload instead.
Useful? React with 👍 / 👎.
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
App side of the Team Library: publish connections and saved queries to your team through your account (not a shared folder), and see the shared set in-app. Team-tier gated. Passwords are never sent. Pairs with the backend PR (TableProApp/license#68).
What's included
ProFeature.teamLibrary(requires the Team tier), reusing the existing tier resolution.ConnectionExportService.buildEnvelope, so no password, passphrase, TOTP secret, or secure plugin field ever leaves the app.TeamLibrarySyncCoordinatorpulls the shared set on the license revalidation cadence (and at launch), caches it via a small actor-backed store, and drives the UI. License access and credentials are injected so it is unit-testable.LicenseAPIClient; the wire format is snake_case via CodingKeys so the embedded connection payload keeps its own encoding.Tests
6 Swift Testing cases (wire-format decode/encode round-trip, gating, pull caching, 7-day cadence, publish mapping). App builds; SwiftLint clean. CHANGELOG and docs updated.
Adversarially reviewed; the main-actor isolation of the publish alert tasks came out of that review.