Skip to content

feat: lower Import UX friction#9643

Merged
jackkav merged 22 commits intoKong:developfrom
jackkav:fix/import-modal-feedback
Feb 16, 2026
Merged

feat: lower Import UX friction#9643
jackkav merged 22 commits intoKong:developfrom
jackkav:fix/import-modal-feedback

Conversation

@jackkav
Copy link
Contributor

@jackkav jackkav commented Feb 6, 2026

Motivation: reduce friction to import collections and single requests and add flexibility to import location.
Goal: make curl a reasonable way to deeplink into the app allowing them to be added separately or in a collection

TODO

  • stretch curl input box and fix overflow
  • add warning to top
  • add origin param
  • improve curl import code quality
  • improve error handling
  • run validate straight away without hitting scan
  • add project select
  • disable invalid submit
image

future work

  • use curlconverter in order to get more standard fallbacks and errors from bad inputs.

closes INS-1966

@jackkav jackkav changed the title Fix/import-modal-feedback Import UX improvements Feb 6, 2026
@jackkav jackkav force-pushed the fix/import-modal-feedback branch 2 times, most recently from e72b619 to e4a0e2a Compare February 12, 2026 10:16
@jackkav jackkav marked this pull request as ready for review February 12, 2026 14:06
@jackkav jackkav requested review from a team, ZxBing0066, Copilot and gatzjames February 12, 2026 14:06
@jackkav jackkav changed the title Import UX improvements feat: lower Import UX friction Feb 12, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR improves the import UX (notably cURL) by adding source/origin context, immediate cURL validation feedback, and a project/collection selection flow, while also refactoring the cURL importer and aligning importer authentication typing with the main request model.

Changes:

  • Update Import modal UI (warning banner, larger cURL input, inline validation messaging, show origin link, allow selecting a target project/collection).
  • Refactor the cURL importer (better structure, bearer/basic auth parsing changes) and update tests/snapshots accordingly.
  • Align importer authentication typing with RequestAuthentication used by request models.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
packages/insomnia/src/ui/components/modals/import-modal/import-modal.tsx Import modal UX updates (cURL textarea + validation, origin display, project/collection selectors)
packages/insomnia/src/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.request.new.tsx Safer optional chaining for cookie counting
packages/insomnia/src/root.tsx Propagate origin through deep-link import params
packages/insomnia/src/main/importers/importers/openapi-3.ts Remove old Authentication type usage and rely on updated typing
packages/insomnia/src/main/importers/importers/curl.ts Refactor cURL parsing/building; add bearer/basic auth extraction changes
packages/insomnia/src/main/importers/importers/curl.test.ts Rewrite/condense cURL tests for refactored importer
packages/insomnia/src/main/importers/importers/snapshots/index.test.ts.snap Snapshot update for auth shape (basic includes type)
packages/insomnia/src/main/importers/entities.ts Replace custom Authentication with `RequestAuthentication
packages/insomnia/src/common/import.ts Rename default imported workspace label to “Imported Collection”
Comments suppressed due to low confidence (1)

packages/insomnia/src/ui/components/modals/import-modal/import-modal.tsx:503

  • ImportResourcesForm's onImport prop signature was changed to include selectedProjectId, but the call sites still pass only selectedWorkspaceId (e.g. the Import button). This will shift arguments so the selected workspace id is treated as the project id, leading to imports targeting the wrong project/workspace. Update the handler plumbing so the Import button passes (overrideBaseEnvironmentData, selectedProjectId, selectedWorkspaceId) and the parent ImportModal uses selectedProjectId when submitting the import action.
}: {
  scanResults: ScanResult[];
  errors?: string[];
  onImport: (overrideBaseEnvironmentData: boolean, selectedProjectId?: string, selectedWorkspaceId?: string) => void;
  disabled: boolean;
  loading: boolean;
  isImportingBaseEnvironmentToWorkspace: boolean;
}) => {

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 118 to 123
const extractHeaders = (pairsByName: PairsByName) => {
return [...((pairsByName.header as string[] | undefined) || []), ...((pairsByName.H as string[] | undefined) || [])]
.filter(header => {
const [name, value] = header.split(/:(.*)$/);
return isBearerAuth(name, value) === false;
})
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

extractHeaders filters out bearer auth headers by splitting on : and calling isBearerAuth(name, value), but value can be undefined for malformed headers (no colon). This will throw before the later if (!value) handling. Ensure isBearerAuth handles missing values or default value to an empty string before calling it.

Copilot uses AI. Check for mistakes.

import type { Parameter } from '../entities';
import { convert } from './curl';
import { convert, name } from './curl';
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

Unused import: name is imported from ./curl but never referenced in this test file. This will fail lint/typecheck in many setups; remove it or use it in an assertion.

Suggested change
import { convert, name } from './curl';
import { convert } from './curl';

Copilot uses AI. Check for mistakes.
Comment on lines 348 to 388
const validateCurl = async (isMounted: boolean, value: string) => {
if (!value) {
isMounted && setMessage('Invalid cURL request');
return;
}
try {
const { data } = await window.main.parseImport(
{
contentStr: value,
},
{
importerId: 'curl',
},
);
const { resources } = data;
const importedRequest = resources[0];
isMounted &&
setMessage(
importedRequest.url
? `Detected ${importedRequest.method} request to ${importedRequest.url}`
: 'Invalid cURL request',
);
} catch (error) {
console.log('[importer] error', error);

isMounted &&
setMessage(
error.message.includes('No importers found for file')
? 'Invalid cURL request'
: error.message.replace("Error invoking remote method 'parseImport': Error: ", ''),
);
}
};
useEffect(() => {
let isMounted = true;

validateCurl(isMounted, from?.type === 'curl' && from.defaultValue ? from.defaultValue : '');
return () => {
isMounted = false;
};
}, [from]);
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

The isMounted guard in validateCurl doesn't work as intended: you're passing a boolean value into the async function, so setting isMounted = false in the cleanup won't affect an in-flight validation (it captured true). This can still call setMessage after unmount. Use a mutable ref (e.g. useRef(true)) or close over the isMounted variable directly (don’t pass it as a parameter), or use an AbortController/sequence id to ignore stale results.

Copilot uses AI. Check for mistakes.
Comment on lines 362 to 369
const { resources } = data;
const importedRequest = resources[0];
isMounted &&
setMessage(
importedRequest.url
? `Detected ${importedRequest.method} request to ${importedRequest.url}`
: 'Invalid cURL request',
);
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

resources[0] is used without checking resources.length. If parseImport returns an empty resources array for invalid input, importedRequest will be undefined and importedRequest.url will throw. Guard against an empty result before reading url/method and set an appropriate message.

Copilot uses AI. Check for mistakes.
Comment on lines 373 to 378
isMounted &&
setMessage(
error.message.includes('No importers found for file')
? 'Invalid cURL request'
: error.message.replace("Error invoking remote method 'parseImport': Error: ", ''),
);
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

In the catch block, error is unknown and may not have a .message property. Accessing error.message can throw and mask the original failure. Narrow with error instanceof Error (or safely stringify) before reading message, and avoid relying on exact remote-method prefix strings for parsing.

Suggested change
isMounted &&
setMessage(
error.message.includes('No importers found for file')
? 'Invalid cURL request'
: error.message.replace("Error invoking remote method 'parseImport': Error: ", ''),
);
const rawMessage =
error instanceof Error
? error.message
: String(error);
const cleanedMessage = rawMessage.replace(
"Error invoking remote method 'parseImport': Error: ",
'',
);
const finalMessage = rawMessage.includes('No importers found for file')
? 'Invalid cURL request'
: cleanedMessage;
isMounted && setMessage(finalMessage);

Copilot uses AI. Check for mistakes.
Comment on lines 465 to 474
{from?.type === 'curl' && from.origin && (
<div className="flex w-full justify-start py-1">
<CurlIcon />
cURL from{' '}
<Link className="px-2 font-bold underline" href={from.origin}>
{' '}
{from.origin}{' '}
</Link>{' '}
⚠️
</div>
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

from.origin is untrusted input (comes from URL params) and is being placed directly into an anchor href via react-aria-components Link. This can enable javascript:/unexpected schemes in a clickable link. Prefer the app’s ~/ui/components/base/link (which routes through window.main.openInBrowser) and/or validate/allowlist schemes (http/https) before rendering/clicking.

Copilot uses AI. Check for mistakes.
@jackkav jackkav force-pushed the fix/import-modal-feedback branch from 7e4b656 to e80762a Compare February 13, 2026 11:28
@jackkav jackkav force-pushed the fix/import-modal-feedback branch from e80762a to 2bc6ea4 Compare February 16, 2026 08:07
@jackkav jackkav enabled auto-merge (squash) February 16, 2026 08:12
@jackkav jackkav merged commit 5b6c59d into Kong:develop Feb 16, 2026
10 checks passed
@jackkav jackkav deleted the fix/import-modal-feedback branch February 16, 2026 08:22
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.

3 participants