Skip to content

feat(environment): add Environment menu with variable substitution and status indicators#73

Open
KhenCahyo13 wants to merge 24 commits intosunchayn:basefrom
KhenCahyo13:feat/environment-variables
Open

feat(environment): add Environment menu with variable substitution and status indicators#73
KhenCahyo13 wants to merge 24 commits intosunchayn:basefrom
KhenCahyo13:feat/environment-variables

Conversation

@KhenCahyo13
Copy link

@KhenCahyo13 KhenCahyo13 commented Mar 9, 2026

Description

This PR introduces a new Environment menu to manage environment variable collections and use them in request building/execution (The concept is actually the same as Postman and similar tools).

It also adds placeholder status indicators in request inputs:

  • Missing variable in active collection -> destructive/red
  • Variable exists but empty -> warning/orange
  • Variable exists with value -> primary

Motivation

Users need a way to define reusable variables (e.g. tokens, host parts, query values) and inject them into requests using {{variable}} syntax.

This improves request reuse and reduces manual editing across endpoints, headers, auth fields, and body payloads.

Changes

  • Added new Environment page and sidebar navigation entry.
  • Added useEnvironmentVariablesStore with persisted collections.
  • Added variable substitution resolver for:
    • endpoint
    • query parameter values
    • header values
    • authorization text inputs
    • JSON/string/form-data string payloads before request execution
  • Added placeholder status evaluation utility (missing | empty | resolved).
  • Added UI indicators for status in:
    • endpoint input
    • key-value parameter values
    • bearer/basic auth inputs
    • JSON editor (via CodeMirror lint extension)
  • Added tests for:
    • environment store behavior
    • variable resolver/status logic
    • affected request/composable integration points

Important Note / Current Limitation

Environment collections are currently persisted in browser local storage (Pinia persisted state), so they are:

  • local to one browser/device/profile
  • not shareable between users
  • not synchronized across environments

If this feature is approved, we may consider a future enhancement for server-backed/shared environment storage.

How to Test

  1. Open Nimbus and navigate to Environment.
  2. Create a collection, add variables (e.g. token, host, userId), and ensure it is active (Used).
  3. In request builder, use placeholders such as:
    • endpoint: /api/{{host}}/users
    • bearer token: {{token}}
    • JSON body: { "id": "{{userId}}" }
  4. Verify placeholder status indicators:
    • missing key -> red
    • existing but empty value -> orange
    • existing with value -> primary
  5. Execute request and verify placeholders are resolved in outbound request payload.
  6. Reload page and verify collections persist.

Screenshots

Environment Page

Screenshot 2026-03-09 at 19 41 17

Variables Indicator

Screenshot 2026-03-09 at 19 41 46

Related

N/A

@sunchayn sunchayn self-requested a review March 9, 2026 22:59
Copy link
Owner

@sunchayn sunchayn left a comment

Choose a reason for hiding this comment

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

Thank you for your contribution 🙏

I left some questions and suggestions.

Some of the variabes like the base endpoint, make sense to be configurable instead, which will also make the collaboration more consistent. This can be combined with something I have in mind in the future to have configuration per environment (which some Nimbus features, being disabled like cookie decryption, can only work when the current and target environments are the same).


In the subject of collaboration, how will this work with shareable links? When the consumer doesn't have the same env variables configured in their localstorage?

export const fallbackExtensions = (readonly: boolean): Extension[] =>
commonExtensions(readonly);

const placeholderPattern = /{{\s*([^{}]+?)\s*}}/g;
Copy link
Owner

Choose a reason for hiding this comment

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

[this is is an overall question]

What if the user wants to actually use literal '{{ .. }}' but not necessarily substitute it with a variable?

[suggestion, perhaps future iteration]

The way I see it, a UX friendly way would be to show a dropdown when the user starts typing, they can either pick an option or continue typing. When they fully type a variable, there will be only one option in the dropdown. They will have to either click on it or type Enter to confirm; pressing space after the variable closing tag or clicking outside of the variable boundaries will hide the dropdown. Wdyt?

Copy link
Author

@KhenCahyo13 KhenCahyo13 Mar 11, 2026

Choose a reason for hiding this comment

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

Yes sir, your suggestion is right, when the user type an variable name, they will get some suggesstions from an dropdown (its like autocomplete). I thought about this feature also, but i'm still hold it, i will make this one if you agree with this feature 🙏🏼.

Copy link
Owner

@sunchayn sunchayn Mar 12, 2026

Choose a reason for hiding this comment

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

Yes, an auto-complete dropdown will be a great UX here 🙏 But let's first stabilize the implementation before making UX improvements to make sure they are done on a final architecture.

@KhenCahyo13
Copy link
Author

KhenCahyo13 commented Mar 11, 2026

For shareable environment, i have some suggestions sir:

  1. We can create Export feature (as json) which is, it will export all of the environment collections and the related variables, then another user can Import this file so they will have same environment config. But it has small disadvantages, how when the user create some new variables or collections? Are we still share the file again and again? But, i thought it just small problem, because average environment values come from Backend developer and Frontend developer just use those values. But how about when we have more than 1 Backend developer? 😅
  2. If we need a realtime environment collaboration, we can make this, but it may a little bit effort 😅. We must design the environment migration, ownership, visibility, change conflict, and secret handling.

Wdyt sir? For local storage we must keep this for persist environment per user.

@sunchayn
Copy link
Owner

For shareable environment, i have some suggestions sir:

  1. We can create Export feature (as json) which is, it will export all of the environment collections and the related variables, then another user can Import this file so they will have same environment config. But it has small disadvantages, how when the user create some new variables or collections? Are we still share the file again and again? But, i thought it just small problem, because average environment values come from Backend developer and Frontend developer just use those values. But how about when we have more than 1 Backend developer? 😅

If we substitute the env variables directly and send them to the request store as plain texts, the shareable links will work fine because the request builder store will have plain values (instead of the variables). Meaning that, when it is shared, the other consumer will receive the "output" of the substitution across the board. But they will lose the source of the env variable, which is a fine compromise for now. Perhaps in the future we can make the environment variables shareable as well within the same link, but it needs dedicated thinking. The URL length is limited, so the less data we carry the better.

  1. If we need a realtime environment collaboration, we can make this, but it may a little bit effort 😅. We must design the environment migration, ownership, visibility, change conflict, and secret handling.

This is another day's problem. It will require a "server" in between to keep things in sync. It is too early to go in that direction.

Copy link
Owner

@sunchayn sunchayn left a comment

Choose a reason for hiding this comment

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

Thanks for the updates!

parameter.value,
activeVariables.value,
activeVariablesMap.value,
);
Copy link
Owner

Choose a reason for hiding this comment

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

[question]

The way this works is a bit hard to follow mentally. I don't fully follow how this will be mapped to the input. It is coming from the store, and I assume the getEnvironmentPlaceholderStatus is reactive. But it is reactive to what? All inputs on the page? What if there are many inputs on the page and they all have different statuses (theoretically), how will the status react independently for each input?

Copy link
Author

Choose a reason for hiding this comment

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

In the context of getEnvironmentPlaceholderStatus, this is reactive, and this is reactive for indicator status for related variable. This work only on Authorization, Headers, Body (JSON, Form Data), and Parameters.

For the case many inputs it will reacted based on the variable key sir, if there is an value or not on the related variable key, so it will update the indicator status (in this case placeholder status) based on the value.

KhenCahyo13 and others added 12 commits March 13, 2026 13:16
Co-authored-by: Mazen Touati <14861869+sunchayn@users.noreply.github.com>
…olvedRequest

Enhance the useResolvedRequest composable to expose individual resolved request
components (endpoint, headers, body, queryParameters) as reactive computed
properties. This enables more decoupled and maintainable component consumption,
allowing consumers to use only the specific resolved values they need.

The composable now provides:
- resolvedEndpoint: reactive endpoint with substituted variables
- resolvedHeaders: reactive headers with substituted variables
- resolvedBody: reactive body with substituted variables
- resolvedQueryParameters: reactive query parameters with substituted variables

The original resolveRequest() method is retained for backward compatibility.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… access

Add a 'variables' computed property to useEnvironmentVariablesStore that
automatically resolves to the current environment's global variables. This
simplifies the consumer API by eliminating the need to understand the
'collections' concept.

Consumers now use store.variables instead of store.activeCollection?.variables,
reducing cognitive load and providing better decoupling. The variables property
automatically tracks the active collection selection.

Update useResolvedRequest to use the new variables property for cleaner access
to active environment variables.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…er status

Add EnvironmentVariablePlaceholderIndicator component that wraps any input
with a hover popover showing contextual info when a placeholder is Missing,
Empty, or Resolved. Apply it across all indicator usages (KeyValueParameters,
auth inputs, endpoint input).

Refactor getValueInputStatus and reactive env variable helpers into
utils/ui/environment-variable to eliminate duplication across components.
Also fix broken getValueInputExtraClassUsing prop name that prevented
indicator colors from working in KeyValueParameters.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…dRequest

- Accept optional reactive request ref to return truly granular ComputedRef<T>
  per field, instead of ComputedRef<(req) => T> which never re-evaluated on
  store changes
- Fix lazy store access in environment-variable util to avoid calling
  useEnvironmentVariablesStore() at module level (broke component tests)
- Add tests covering reactive property defaults, placeholder resolution,
  reactivity to variable/request changes, and imperative resolveRequest use

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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