feat: Integrate Resource Browsers#183
Conversation
3b6823d to
f9477f6
Compare
Design-time artifacts for merging AWS Inspector's resource-browsing views into the LocalStack Toolkit: proposal, design, per-capability specs (focus-model, localstack-explorer-view, resource-browser, localstack-metamodel), tasks, and a captured metamodel sample. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ing cleanup Explore view UX refinements (rounds 3-5): - Title Case command/menu labels; "All Resources" -> "View All Resources" - Cloud Profiles / region / view row actions shown as inline icons (pencil/pencil/plus/trash, plus pencil+trash on view rows) and in the right-click context menu; "Add View..." moved off a tree row - Adaptive settings persistence: write to Workspace when a folder is open, else Global, fixing "Unable to write to Workspace Settings" with no folder ESLint typing cleanup: - Remove the ported-AWS-code exception block in eslint.config.mjs and fix the ~62 no-unsafe-* errors at the source: typed `memoize` generic, typed SDK client wrappers (getQueueAttributes/getTopicAttributes/listStackResources), typed INI parsing in awsConfig, and the metamodel JSON-parse boundary Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Implements Section 18 of integrate-resource-browsers: - blank icon by default on tree rows (section headers excepted) - Edit View action uses the gear icon - invert profile visibility to opt-in (cloudProfiles.shown), default to the `default` profile (or first when none named default), with a "No profiles selected" placeholder for an explicit empty set - omit the account-alias separator when the alias is empty - rename CloudFormation selectors "CFN:" -> "Stack:" - modal confirmation before removing a region or a view - manual refresh buttons on the Resources and Resource Details views Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Resources/Details refresh recomputes the focus (re-queries the
LocalStack metamodel) instead of re-rendering a cached structure.
- Route all service clients through AWSConfig.getClientConfig so the
localstack profile's endpoint is honored — fixes the spurious
"security token included in the request is invalid" against real AWS.
- Merge the service and resource-type tree levels into one row
(label = service, dimmed description = resource type), one row per
service/resource-type pair; service icon on that row, none on leaves.
- Views are defined by selecting service/resource-type pairs;
SavedFilter now stores a flat { service, resourceType } list.
- Rewrite Resource Details as a themed webview table with per-FieldType
formatting (JSON/long-text blocks, monospace ARNs); interactions
deferred.
- Drop the blanket default "blank" tree icon, keeping only the one that
aligns the instance's "View: All Resources" with "App Inspector".
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Failed, rolled-back, and deleting stacks passed the previous status filter but have no live resources (or resources lacking a PhysicalResourceId), so clicking them threw "Cannot read properties of undefined (reading 'split')" and the Resources view stayed empty. Narrow listStacks to the stable, resource-bearing terminal states so such stacks never appear in the Explore view. As defense-in-depth, convertToServicesList now skips (and warns about) any individual resource it can't map instead of aborting the whole stack; CfnStackModel takes an explicit LogOutputChannel for those warnings. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add ported model tests completing task 3.5: - awsConfig.test.ts: profile listing, region resolution (file + AWS_REGION precedence), endpoint_url surfacing, missing-file fallback - cfnStackModel.test.ts: stack-resource -> Focus conversion, same-type grouping, and the per-resource skip/warn behavior (covers the previously-fatal missing-ResourceType case) Sync the change's delta specs into openspec/specs/ (focus-model, localstack-explorer-view, localstack-metamodel, resource-browser) and archive the completed integrate-resource-browsers change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The archive commit captured tasks.md before the working-tree checkbox updates were staged. Bring the archived task list in sync with the actual completion state (3.5 model tests + the manual-verification tasks). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rative providers Introduce a static, coverage-derived service manifest as the single source of truth for supported AWS services, a declarative provider engine, a build-time detail-field generator, manifest-backed provider registration with a completeness tracker, and Batch 1 (10 curated services, 26 resource types). - manifest: build/generate-service-manifest.mjs -> resources/service-manifest.json (116 services); memoized loader + shared label mapping (stepfunctions -> states) - declarative engine: defineService/defineResourceType + DeclarativeServiceProvider (list, identifier mapping incl. region-synthesized ARNs, path-walked detail, matchArn, CFN mapping); imperative ServiceProvider kept as the escape hatch - detail-field generator: build/generate-detail-fields.mjs (importance heuristic) - ProviderFactory resolves by manifest id, no generic fallback; default icon path - cfnStackModel + metamodelFocus use the shared label mapping; Resources leaf tolerates non-ARN identifiers - Batch 1: S3, API Gateway, SSM, Secrets Manager, Kinesis, CloudWatch Logs, EventBridge, KMS, Cognito (cognito-idp; IdentityPool deferred), ECR Deferred: migrating the 7 imperative providers to declarative; manual emulator/ cloud verification. 105 tests passing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The per-service icons in the Resources view were hand-edited derivatives of AWS's Architecture Icons; bundling AWS iconography in the product risks violating AWS's icon terms of use. Remove the 6 derivative SVGs and the per-service icon API, and instead show an icon that reflects the profile's target: the LocalStack mark for LocalStack-targeted profiles and the built-in `cloud` codicon for real AWS. Both are themed ThemeIcons with no AWS IP. - Delete resources/icons/services/*.svg and ServiceProvider.getIconPath (plus the now-dead `context` plumbing through the provider chain) - Add AWSConfig.getEndpointForProfile; resolve isLocalStack per profile in viewProvider and thread it to the service-and-resource-type row - Update the resource-browser spec; add tree-item icon and getEndpointForProfile tests - Archive the remove-aws-service-icons OpenSpec change Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Remove unused StandardModel/loadStandardModel and resources/focuses/
- Rename src/views/localstack → src/views/explore to match the view name
- Migrate internal "filter" terminology to "view" (cloud-profile views):
SavedView/ViewScope, getProfileViews, saveProfileView, removeProfileView,
ProfileViewTreeItem, resolveRegionViewFocus, command IDs
localstack.{add,edit,remove}ProfileView, contextValue localstackProfileView,
and config key cloudProfiles.views
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…efinitions Migrate the seven hand-written ServiceProvider subclasses (CloudFormation, DynamoDB, IAM, Lambda, SNS, SQS, Step Functions) to declarative ServiceDefinitions executed by the engine, and delete the now-orphaned client wrappers. IMPERATIVE_PROVIDERS is now an empty (documented) escape hatch. Add a `list` detail-spec to the declarative engine/types so variable-length sections (DynamoDB attributes/key schema, CloudFormation parameters/outputs) can be expressed declaratively — the one capability the FieldSpec model previously lacked. Behavior preserved incl. CFN mapping (SQS queue-URL split, Lambda type-prefixed names, States still unmapped) and metamodel op maps. Two intentional normalizations to match existing declarative providers: no redundant "Resource Type" row, and missing values render as "" rather than "N/A". Add engine list-spec tests and a batch2 provider test suite. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
getRegionLongName threw for any region missing from its hardcoded table, so a single such region in the running emulator's metamodel (e.g. cn-north-1) aborted the whole "All Resources" view. It now degrades to the region code for unknown regions, and the China partition (cn-north-1, cn-northwest-1) is added to the table. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…esources Opening an API Gateway or Cognito resource from a Stack view threw "Cannot resolve resource type for ARN". The live `list` path and the CloudFormation path synthesize ARNs differently, and these multi-type services rely on the engine's "self" describe path, which requires the synthesized ARN to string-equal the live `id` — but the CFN template always injects an account segment the live `id` omits. Fix the 4 types CloudFormation can support by re-encoding the discriminating token via cfnResourceName and adding a direct describe() (also removes the per-click re-list for the API Gateway types): - cognito userpool, apigateway restapi/apikey/usageplan Drop the cfn mapping for the 4 it cannot: their PhysicalResourceId is the leaf id only, without the parent pool/api id every describe API needs, so CFN-origin resolution is impossible. They are now skipped and logged in stack views (as the states definition does) rather than throwing on click; live resources still resolve. - cognito userpoolclient/userpoolgroup, apigateway stage/authorizer Add cfnRoundTrip.test.ts covering synthesize -> resolve -> describe for the 4 fixed types and asserting the 4 dropped types are unmapped. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
memoize() cached only a promise's resolved value, set inside .then(), so concurrent callers each fired their own request before the first resolved — defeating the cache exactly during tree expansion, when many nodes resolve at once. Cached data also lived for the whole session with no way to invalidate, so the refresh button replayed stale account ids / region lists and never picked up re-authenticated credentials. Cache the promise itself (concurrent callers now share one in-flight request) and evict it on rejection so failures aren't served forever. Add clear() per memoized function plus a registry-backed clearMemoizedCaches(), and wire it into the refreshResources command so a manual refresh re-queries AWS and rebuilds clients (also picking up an endpoint change for the profile-only-keyed clients). Add memoize.test.ts covering dedup, rejection-eviction, and clear paths. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Relocate the Resource Details webview from the left activity-bar container to its own bottom-panel container (localstackPanel), giving the key/value table room to breathe. Explore and Resources stay in the sidebar, now split 50/50 by default (Resources size 2 -> 1). Selecting a resource reveals the panel via WebviewView.show(true), which brings the tab forward without stealing keyboard focus, so arrow-key browsing in the Resources tree keeps working and details follow live. The first reveal (before the view has resolved) falls back to the auto- generated <viewId>.focus command to open the panel. Also cap the Resource Details field-label column at 20% (was 33%); the fixed table layout makes that a hard cap so long labels wrap rather than widen the column. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Unpin all @aws-sdk/client-* from exact 3.901.0 to ^3.901.0 so they track updates rather than staying on an old pin; re-resolving lands on 3.1070.0 (the newest version past the 7-day cooldown). Regenerate pnpm-lock.yaml so a clean `pnpm install` passes the repo's supply-chain policies: - minimumReleaseAge: the previously-fresh @smithy transitive deps now resolve to aged versions automatically on re-resolution. - no-downgrade: add version-scoped trustPolicyExclude for chokidar@4.0.3, semver@5.7.2, semver@6.3.1, and undici-types@6.21.0 — all confirmed benign provenance gaps (maintainers dropped npm provenance on those specific releases and restored it later), not takeovers. Add keepNames to the esbuild config so class names survive bundling. The AWS SDK bump triggered an esbuild identifier collision (e.g. DescribeKeyCommand -> DescribeKeyCommand2) that broke the provider tests' constructor.name dispatch. Fix `vsce package`: compile no longer runs through npm-run-all, which spawned the corepack-managed pnpm shim directly and failed with EACCES (the cached pnpm.cjs has no execute bit). compile now invokes esbuild and vite directly with && for correct failure propagation; the redundant compile:extension/compile:appinspector-webview sub-scripts are removed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Hide the Resources and Resource Details views behind the localstack.resourceBrowserEnabled context flag, and add enable/disable commands to toggle the preview on and off. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move the completed change into the dated archive and apply its delta specs to the main specs: add resource-browser opt-in gating and opt-in/ opt-out affordance requirements to the explorer view, and the opt-in visibility requirement to the resource browser. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
889c401 to
b970d54
Compare
Thanks for the feedback. I'd be interested to know if there's are better ways of achieving the "resource browser" goal, so I welcome ideas. The basic idea is to select a "Focus" in the top view, which lets the user decide what they want to look at:
Once that is selected, the "Resources" view shows the content of the thing the user wanted to focus on. This is a new concept that I haven't seen in our resource browsers.
Sounds good, that's easy to do and will reduce complexity.
They are AWS Config Profiles (for AWS), or the equivalent for Azure. The reason they exist is because users should be able to browser both their LocalStack resources as well as AWS / Azure resources using the same interface. If we only supported LocalStack, and not the cloud providers, that would limit the usefulness of this tool, especially in hybrid situations. I do get your point about the multi-region discrepancy though - Perhaps having a similar per-region filter on the LocalStack interface would help? Perhaps there's some way to combine the two sections (LocalStack Instances and Cloud Profiles) into one?
Yes, it shows the content of whatever you've selected in the Focus area. This is perhaps the UX that needs some rethinking. People are familiar with the regular per-region breakdown that AWS Toolkit has, but they're not familiar with browsing the content of a CloudFormation stack.
Thanks, that's a good addition.
Agreed - it currently uses a custom API in LocalStack to fetch the resource definitions, rather than the standard AWS SDKs. Therefore, we could add WebSockets for live updates. The biggest challenge would be getting every service to emit events when it CRUDS a resource. As for whether to merge, I'd still like to proceed, but with it being an opt-in preview feature. That will allow us to get more hands-on experience, and iterate over time. There's definitely value in having a Resource Browser in the LocalStack Toolkit, but I agree that the "Explore" window needs some UX love (from you and @gtsiolis ) to make it easier to use. |
|
The other consideration is that "LocalStack Instances" is different/separate from "Cloud Profiles" because it has added-value features, such as App Inspector, Snapshots, etc. We'd need a place to put those buttons/features, which is not relevant in the Cloud Profiles section. |

This PR introduce "Resource Browsers" into the LocalStack Toolkit, similar to the feature we already have in the LocalStack Console, but more aligned with the IDE-centric way of viewing resources.
The LocalStack View Container now contains three views:
Notes:
openspec/changes/archive/2026-06-23-integrate-resource-browser/proposal.mdandopenspec/changes/archive/2026-06-23-integrate-resource-browser/design.mdfor an overview.