Repository navigation
Feature/studio apps action - #220
Merged
Merged
Conversation
…ppId
Extend the platform layer so Client Home can discover Studio apps' action
labels and bucket notifications by app.
- AppInstallsDataSchema: add icon, disabled, isDraft, isInternalApp
- Add ActionLabelSchema + InstallNotificationSettingsSchema for
GET /v1/installs/{id}/notification-settings, plus isActionLabelRegistered
- NotificationsResponseSchema: add appId (nullish); relax event to nullish
- AssemblyClient.getInstalls() and getInstallNotificationSettings(installId),
the latter via a _manualFetch helper since the SDK exposes no method for
the notification-settings sub-resource
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…orks Check response.ok before parsing the body in _manualFetch. A transient 429/500 with a non-JSON body previously threw a statusless SyntaxError, which withRetry could not recognize as retryable. Now read the error body as text and throw APIError with the real status. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Client Home stores only the internal user's per-app hide state as a deny-list keyed by appId (absence = shown), so default-on needs no setup, uninstall needs no cleanup, and reinstall restores the prior choice. - Add hiddenAppIds jsonb column (string[], default []) to actions + migration - Thread through drizzle-zod schemas (ActionsSchema/Create/Update -> DTOs); repository/service pick it up via payload spread - Account for hiddenAppIds in the useAppControls dirty check (array compare, like order) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…var for API URL - Replace the manual isActionLabelRegistered checks with a strict RegisteredActionLabelSchema (trim + non-empty), per PR review - Use env.ASSEMBLY_API_URL (default prod) as the base URL in _manualFetch instead of the SDK's mutable OpenAPI.BASE global; drop the OpenAPI import Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…m-layer-extend-assemblyclient-for-installs OUT-3977 | Platform layer: extend AssemblyClient for installs notificationConfig + notification appId
…ence-add-hiddenappids-to-actions-table-per-app-hide OUT-3978 | Persistence: add hiddenAppIds to actions table (per-app hide state)
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThis PR adds Studio app actions to the client home action list. The main changes are:
Confidence Score: 5/5This looks safe to merge.
Important Files Changed
Reviews (3): Last reviewed commit: "Merge pull request #226 from assemblycom..." | Re-trigger Greptile |
Comment on lines
+38
to
+39
| const hiddenAppIdsChanged = | ||
| JSON.stringify(actions.hiddenAppIds) !== JSON.stringify(initialSettings.actions?.hiddenAppIds) |
There was a problem hiding this comment.
Unordered Deny List Stays Dirty
hiddenAppIds is a deny-list keyed by app ID, so its order has no meaning. If the UI or server returns the same IDs in a different order, this string comparison marks the editor dirty even though the hidden apps did not change, leaving the Save CTA visible on a clean form.
New installed-apps feature module (CLEAN: service + controller + route) that returns Studio app installs eligible for "Your Actions". - Service filters out disabled/draft/internal installs, then fans out getInstallNotificationSettings per install in parallel, keeping only those with a complete registered actionLabel - A single notification-settings failure skips that install, not the request - GET /api/installed-apps (withErrorHandler), authorized for IU and client - useInstalledApps React Query hook ([KEY, workspaceId], Zod-validated) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extend NotificationCountsDto with an `apps` map (appId -> unread count) so dynamic action rows stay in sync with built-in rows via one fetch/hook/cache entry. The counts service buckets the client's unread notifications by appId while preserving the existing recipientCompanyId filter; built-in event-based counts are unchanged. Narrow the actions-card count lookup to the numeric NotificationCountKey type now that the DTO also carries the nested apps map. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…endpoint' into arpandhakal/out-3981-client-ui-dynamic-studio-app-rows-in-your-actions
Synthesize ActionDefinition-shaped rows at runtime from the actionable-installs
discovery endpoint (OUT-3979) and merge them into useEnabledActions after the
built-ins (no drag-order participation in v1), filtered by actions.hiddenAppIds
(OUT-3978, deny-list by appId).
- New DynamicActionDefinition + toDynamicActionDefinition: verb <- actionLabel.verb,
label <- pluralNoun, singularLabel <- singularNoun, icon mapped onto the design
system Icon (fallback CustomApps when the install icon isn't a valid IconType)
- icon-names: runtime allow-list of design-system IconType names, since the package
does not expose its icon registry at runtime
- ActionItem/ActionsCard render the RenderableAction union: dynamic count from the
per-app map (OUT-3980), navigation via postMessage history.push { id: installId,
route: 'apps' }; dynamic rows never render a zero/empty state in any mode
- Widen ActionDefinition.icon to IconType so built-in and dynamic rows share the field
Built-in rows unchanged in behavior and appearance.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Internal users control each Studio app's presence in Your Actions from
the existing Actions sidebar panel. Apps appear automatically once
installed and registered, defaulted to on.
- useActions merges dynamic apps (keyed by appId) after built-ins;
toggle checked = !hiddenAppIds.includes(appId); flipping mutates
actions.hiddenAppIds, saved via the existing Save Changes flow.
- AppToggleItem renders a non-draggable toggle row (Studio-app rows are
excluded from dnd reorder in v1).
- Editor preview now shows every enabled dynamic row regardless of
count, matching built-in behavior, with the {{N}} placeholder chip.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Built-ins and dynamic Studio-app rows now share one drag-orderable list in the Actions sidebar; `order` holds a mix of ActionKeys and appIds, and useEnabledActions renders in that unified order (drops the v1 "apps last, non-draggable" restriction). Removes AppToggleItem; ActionItem icon widened to IconType. - Exclude the Tasks app (appId === TASKS_APP_ID) from actionable-installs discovery so it doesn't duplicate the built-in Tasks row. - Fan out notification-settings via mapWithConcurrency (limit 5) instead of Promise.all, avoiding a TLS-connection burst that tripped undici connect timeouts in dev. - Log both the raw platform installs and the final actionable list to aid debugging why an app does/doesn't surface. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop the temporary logger.info calls for the raw platform installs and the final actionable list; keep the error log for failed notification-settings fetches. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…studio-app-toggles-in-actions-sidebar-preview-rows OUT-3982 | Editor: Studio app toggles in Actions sidebar + preview rows
…ui-dynamic-studio-app-rows-in-your-actions OUT-3981 | Client UI: dynamic Studio app rows in Your Actions
…-app-unread-notification-counts OUT-3980 | API: per-app unread notification counts
App builders register `actionLabel.verb` with no casing rule enforced, so it
arrives in whatever shape the app author typed ("review", "reView", "REVIEW").
Normalize it to sentence case in `toDynamicActionDefinition`, the single funnel
for Studio app action labels into the render path.
Nouns pass through verbatim since they render mid-phrase. Pre-existing built-in
actions keep their hardcoded verbs.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ize-actionlabel-verb-usage OUT-4014 | Capitalize actionLabel verb usage
Collaborator
Author
|
@greptile review again please. |
1 of 4 tasks
`hiddenAppIds` is an unordered deny-list, but the toggle path rebuilds it by filter-then-append, so a hide/unhide/hide cycle returns the same members in a different position. The serialized comparison read that as a change and left Save/Cancel visible on a clean form. Adds `areArraysEqualAsSets` and uses it for `hiddenAppIds` only — `order` is a genuine sequence and keeps its serialized comparison. Reported by Greptile on #220. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ds-set-comparison fix: compare hiddenAppIds as a set for editor dirty state
Collaborator
Author
|
please re review @greptile |
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Changes