Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 44 additions & 1 deletion packages/insomnia/src/common/get-workspace-label.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,49 @@
import { isDesign, isEnvironment, isMcp, isMockServer, type Workspace } from '../models/workspace';
import type { IconProp } from '@fortawesome/fontawesome-svg-core';

import { isDesign, isEnvironment, isMcp, isMockServer, type Workspace, type WorkspaceScope } from '../models/workspace';
import { strings } from './strings';

export type ProjectScopeKeys = WorkspaceScope | 'unsynced';

export const scopeToLabelMap: Record<
ProjectScopeKeys,
'Document' | 'Collection' | 'Mock Server' | 'Unsynced' | 'Environment' | 'MCP Client'
> = {
'design': 'Document',
'collection': 'Collection',
'mock-server': 'Mock Server',
'unsynced': 'Unsynced',
'environment': 'Environment',
'mcp': 'MCP Client',
};

export const scopeToIconMap: Record<ProjectScopeKeys, IconProp> = {
'design': 'file',
'collection': 'bars',
'mock-server': 'server',
'unsynced': 'cloud-download',
'environment': 'code',
'mcp': ['fac', 'mcp'] as unknown as IconProp,
};

export const scopeToBgColorMap: Record<ProjectScopeKeys, string> = {
'design': 'bg-(--color-info)',
'collection': 'bg-(--color-surprise)',
'mock-server': 'bg-(--color-warning)',
'unsynced': 'bg-(--hl-md)',
'environment': 'bg-(--color-font)',
'mcp': 'bg-(--color-danger)',
};

export const scopeToTextColorMap: Record<ProjectScopeKeys, string> = {
'design': 'text-(--color-font-info)',
'collection': 'text-(--color-font-surprise)',
'mock-server': 'text-(--color-font-warning)',
'unsynced': 'text-(--color-font)',
'environment': 'text-(--color-bg)',
'mcp': 'text-(--color-font-danger)',
};

export const getWorkspaceLabel = (workspace: Workspace) => {
if (isDesign(workspace)) {
return strings.document;
Expand Down
26 changes: 23 additions & 3 deletions packages/insomnia/src/main/git-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2127,16 +2127,22 @@ export const unstageChangesAction = async ({
}
};

function getPreviewItemName(previewDiffItem: { before: string; after: string }) {
function getPreviewItemNameAndScope(previewDiffItem: { before: string; after: string }) {
let prevName = '';
let nextName = '';

let prevScope: WorkspaceScope = 'collection';
let nextScope: WorkspaceScope = 'collection';

try {
const prev = parse(previewDiffItem.before);

if ((prev && 'fileName' in prev) || 'name' in prev) {
prevName = prev.fileName || prev.name;
}
if ('type' in prev) {
prevScope = insomniaSchemaTypeToScope(prev.type);
}
} catch {
// Nothing to do
}
Expand All @@ -2146,11 +2152,17 @@ function getPreviewItemName(previewDiffItem: { before: string; after: string })
if ((next && 'fileName' in next) || 'name' in next) {
nextName = next.fileName || next.name;
}
if ('type' in next) {
nextScope = insomniaSchemaTypeToScope(next.type);
}
} catch {
// Nothing to do
}

return nextName || prevName;
return {
name: nextName || prevName,
scope: nextScope || prevScope,
};
}

export type GitDiffResult =
Expand All @@ -2160,6 +2172,9 @@ export type GitDiffResult =
before: string;
after: string;
};
filepath: string;
scope: WorkspaceScope;
staged: boolean;
}
| {
errors: string[];
Expand Down Expand Up @@ -2190,9 +2205,14 @@ export const diffFileLoader = async ({
after: fileStatus.workdir,
};

const { name, scope } = getPreviewItemNameAndScope(diff);

return {
name: getPreviewItemName(diff) || filepath,
name: name || filepath,
diff,
filepath,
scope,
staged,
};
} catch (e) {
const errorMessage = e instanceof Error ? e.message : 'Error while unstaging changes';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
getAppWebsiteBaseURL,
} from '~/common/constants';
import { database } from '~/common/database';
import { scopeToBgColorMap, scopeToIconMap, scopeToLabelMap, scopeToTextColorMap } from '~/common/get-workspace-label';
import { fuzzyMatchAll, isNotNullOrUndefined } from '~/common/misc';
import { descendingNumberSort, sortMethodMap } from '~/common/sorting';
import * as models from '~/models';
Expand Down Expand Up @@ -85,46 +86,6 @@ import { DEFAULT_STORAGE_RULES } from '~/ui/organization-utils';
import { trackTempProjectOpened } from '~/ui/temp-segment-tracking';
import { invariant } from '~/utils/invariant';

export type ProjectScopeKeys = WorkspaceScope | 'unsynced';
export const scopeToLabelMap: Record<
ProjectScopeKeys,
'Document' | 'Collection' | 'Mock Server' | 'Unsynced' | 'Environment' | 'MCP Client'
> = {
'design': 'Document',
'collection': 'Collection',
'mock-server': 'Mock Server',
'unsynced': 'Unsynced',
'environment': 'Environment',
'mcp': 'MCP Client',
};

export const scopeToIconMap: Record<ProjectScopeKeys, IconProp> = {
'design': 'file',
'collection': 'bars',
'mock-server': 'server',
'unsynced': 'cloud-download',
'environment': 'code',
'mcp': ['fac', 'mcp'] as unknown as IconProp,
};

export const scopeToBgColorMap: Record<ProjectScopeKeys, string> = {
'design': 'bg-(--color-info)',
'collection': 'bg-(--color-surprise)',
'mock-server': 'bg-(--color-warning)',
'unsynced': 'bg-(--hl-md)',
'environment': 'bg-(--color-font)',
'mcp': 'bg-(--color-danger)',
};

export const scopeToTextColorMap: Record<ProjectScopeKeys, string> = {
'design': 'text-(--color-font-info)',
'collection': 'text-(--color-font-surprise)',
'mock-server': 'text-(--color-font-warning)',
'unsynced': 'text-(--color-font)',
'environment': 'text-(--color-bg)',
'mcp': 'text-(--color-font-danger)',
};

export interface InsomniaFile {
id: string;
name: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { href } from 'react-router';

import { parseApiSpec, type ParsedApiSpec } from '~/common/api-specs';
import { database } from '~/common/database';
import { scopeToLabelMap } from '~/common/get-workspace-label';
import { isNotNullOrUndefined } from '~/common/misc';
import { descendingNumberSort } from '~/common/sorting';
import * as models from '~/models';
Expand All @@ -16,7 +17,7 @@ import { invariant } from '~/utils/invariant';
import { createFetcherLoadHook } from '~/utils/router';

import type { Route } from './+types/organization.$organizationId.project.$projectId.list-workspaces';
import { type InsomniaFile, scopeToLabelMap } from './organization.$organizationId.project.$projectId._index';
import { type InsomniaFile } from './organization.$organizationId.project.$projectId._index';

async function getAllLocalFiles({ projectId }: { projectId: string }) {
const projectWorkspaces = await models.workspace.findByParentId(projectId);
Expand Down
7 changes: 1 addition & 6 deletions packages/insomnia/src/ui/components/command-palette.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
} from 'react-aria-components';
import { useNavigate, useParams } from 'react-router';

import { scopeToBgColorMap, scopeToIconMap, scopeToLabelMap, scopeToTextColorMap } from '~/common/get-workspace-label';
import { constructKeyCombinationDisplay, getPlatformKeyCombinations } from '~/common/hotkeys';
import { fuzzyMatch } from '~/common/misc';
import { isGrpcRequest } from '~/models/grpc-request';
Expand All @@ -29,12 +30,6 @@ import { isWebSocketRequest } from '~/models/websocket-request';
import { useRootLoaderData } from '~/root';
import { useCommandsLoaderFetcher } from '~/routes/commands';
import { useInsomniaSyncPullRemoteFileActionFetcher } from '~/routes/organization.$organizationId.insomnia-sync.pull-remote-file';
import {
scopeToBgColorMap,
scopeToIconMap,
scopeToLabelMap,
scopeToTextColorMap,
} from '~/routes/organization.$organizationId.project.$projectId._index';
import { useSetActiveEnvironmentFetcher } from '~/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.environment.set-active';
import { useRemoteFilesLoaderFetcher } from '~/routes/remote-files';
import { AvatarGroup } from '~/ui/components/avatar';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export const GitProjectSyncDropdown: FC<Props> = ({ gitRepository, activeProject

const [isGitBranchesModalOpen, setIsGitBranchesModalOpen] = useState(false);
const [isGitLogModalOpen, setIsGitLogModalOpen] = useState(false);
const [isGitStagingModalOpen, setIsGitStagingModalOpen] = useState(false);
const [isGitStagingModalOpen, setIsGitStagingModalOpen] = useState(true);
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

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

The Git staging modal is incorrectly set to open by default. This should be false to prevent the modal from appearing automatically when the component mounts. This appears to be a debugging leftover that should be reverted before merging.

Suggested change
const [isGitStagingModalOpen, setIsGitStagingModalOpen] = useState(true);
const [isGitStagingModalOpen, setIsGitStagingModalOpen] = useState(false);

Copilot uses AI. Check for mistakes.
const [isGitPullRequiredModalOpen, setIsGitPullRequiredModalOpen] = useState(false);
const [stagingMode, setStagingMode] = useState<StagingModalMode>(StagingModalModes.default);
const [isMigrationModalOpen, setIsMigrationModalOpen] = useState(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ import { useParams } from 'react-router';

import { useGitProjectMigrateLegacyInsomniaFolderActionFetcher } from '~/routes/git.migrate-legacy-insomnia-folder-to-file';

import type { WorkspaceScope } from '../../../models/workspace';
import {
scopeToBgColorMap,
scopeToIconMap,
scopeToLabelMap,
scopeToTextColorMap,
} from '../../../routes/organization.$organizationId.project.$projectId._index';
} from '../../../common/get-workspace-label';
import type { WorkspaceScope } from '../../../models/workspace';
import { Icon } from '../icon';

export const GitProjectMigrationModal: FC<{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import {
import { useParams } from 'react-router';
import { type TreeData, useTreeData } from 'react-stately';

import { Button as BasicButton } from '~/basic-components/button';
import { scopeToBgColorMap, scopeToIconMap, scopeToTextColorMap } from '~/common/get-workspace-label';
import { useAIGenerateActionFetcher } from '~/routes/ai.generate-commit-messages';
import { useGitProjectChangesFetcher } from '~/routes/git.changes';
import { useGitProjectCommitActionFetcher } from '~/routes/git.commit';
Expand Down Expand Up @@ -479,6 +481,8 @@ interface ManualCommitFormProps {
onPullRequired: () => void;
diffChanges: (params: { path: string; staged: boolean }) => void;
setDiscardData: (data: { paths: string[]; filesCount: number }) => void;
stageChanges: (paths: string[]) => void;
unstageChanges: (paths: string[]) => void;
}

const ManualCommitForm: FC<ManualCommitFormProps> = ({
Expand All @@ -490,10 +494,10 @@ const ManualCommitForm: FC<ManualCommitFormProps> = ({
onPullRequired,
diffChanges,
setDiscardData,
stageChanges,
unstageChanges,
}) => {
const commitFetcher = useGitProjectCommitActionFetcher();
const stageChangesFetcher = useGitProjectStageActionFetcher();
const unstageChangesFetcher = useGitProjectUnstageActionFetcher();

const stagedCount = changes.staged.length;
const unstagedCount = changes.unstaged.length;
Expand All @@ -504,20 +508,6 @@ const ManualCommitForm: FC<ManualCommitFormProps> = ({
const isCommitting = commitFetcher.state !== 'idle';
const canCommitAndPull = stagedCount > 0 && unstagedCount === 0;

function stageChanges(paths: string[]) {
stageChangesFetcher.submit({
projectId,
paths,
});
}

function unstageChanges(paths: string[]) {
unstageChangesFetcher.submit({
projectId,
paths,
});
}

const hasNoCommitErrors =
commitFetcher.data && 'errors' in commitFetcher.data && commitFetcher.data.errors?.length === 0;

Expand Down Expand Up @@ -899,7 +889,7 @@ export const GitProjectStagingModal: FC<{
const { isGenerateCommitMessagesWithAIEnabled } = useAIFeatureStatus();

function diffChanges({ path, staged }: { path: string; staged: boolean }) {
diffChangesFetcher.load({
return diffChangesFetcher.load({
projectId,
filePath: path,
staged,
Expand Down Expand Up @@ -972,6 +962,25 @@ export const GitProjectStagingModal: FC<{
});
}, [commitGenerationKey, generateCommitsFetcher, projectId, commitGenerationCompleted]);

const stageChangesFetcher = useGitProjectStageActionFetcher();
const unstageChangesFetcher = useGitProjectUnstageActionFetcher();
function stageChanges(paths: string[]) {
return stageChangesFetcher.submit({
projectId,
paths,
});
}

function unstageChanges(paths: string[]) {
return unstageChangesFetcher.submit({
projectId,
paths,
});
}

const showManualCommitForm =
!generateCommitsFetcher.data || (generateCommitsFetcher.data && 'error' in generateCommitsFetcher.data);

return (
<>
<ModalOverlay
Expand All @@ -982,12 +991,7 @@ export const GitProjectStagingModal: FC<{
isDismissable
className="fixed top-0 left-0 z-10 flex h-(--visual-viewport-height) w-full items-center justify-center bg-black/30"
>
<Modal
onOpenChange={isOpen => {
!isOpen && onClose();
}}
className="flex h-[calc(100%-var(--padding-xl))] w-[calc(100%-var(--padding-xl))] flex-col rounded-md border border-solid border-(--hl-sm) bg-(--color-bg) p-(--padding-lg) text-(--color-font)"
>
<Modal className="flex h-[calc(100%-var(--padding-xl))] w-[calc(100%-var(--padding-xl))] flex-col rounded-md border border-solid border-(--hl-sm) bg-(--color-bg) p-(--padding-lg) text-(--color-font)">
<Dialog
data-loading={gitChangesFetcher.state === 'loading' ? 'true' : undefined}
className="flex h-full flex-1 flex-col overflow-hidden outline-hidden data-loading:animate-pulse"
Expand Down Expand Up @@ -1088,8 +1092,7 @@ export const GitProjectStagingModal: FC<{
/>
)}

{(!generateCommitsFetcher.data ||
(generateCommitsFetcher.data && 'error' in generateCommitsFetcher.data)) && (
{showManualCommitForm && (
<ManualCommitForm
projectId={projectId}
mode={mode}
Expand All @@ -1099,14 +1102,38 @@ export const GitProjectStagingModal: FC<{
onPullRequired={handlePullRequired}
diffChanges={diffChanges}
setDiscardData={setDiscardData}
stageChanges={stageChanges}
unstageChanges={unstageChanges}
/>
)}
</div>
{previewDiffItem?.diff ? (
<div className="flex h-full flex-col gap-2 overflow-y-auto pb-0">
<Heading className="flex items-center gap-2 font-bold">
<Icon icon="code-compare" />
{previewDiffItem.name}
<div className="flex h-full shrink-0 items-center gap-2 rounded-xs bg-(--hl-xs) pr-2 text-sm text-(--color-font)">
<div
className={`${scopeToBgColorMap[previewDiffItem.scope]} ${scopeToTextColorMap[previewDiffItem.scope]} flex h-[20px] w-[20px] items-center justify-center rounded-s-sm px-2`}
>
<Icon icon={scopeToIconMap[previewDiffItem.scope]} />
</div>
<span>{previewDiffItem.name}</span>
</div>
<span className="font-light">{previewDiffItem.filepath}</span>
{showManualCommitForm && (
<BasicButton
onPress={async () => {
await (previewDiffItem.staged
? unstageChanges([previewDiffItem.filepath])
: stageChanges([previewDiffItem.filepath]));
await diffChanges({
path: previewDiffItem.filepath,
staged: !previewDiffItem.staged,
});
}}
>
{!previewDiffItem.staged ? 'Stage all changes' : 'Changes are staged'}
</BasicButton>
)}
</Heading>
{previewDiffItem && (
<div className="flex-1 overflow-hidden rounded-xs bg-(--hl-xs) p-2 text-(--color-font)">
Expand Down
Loading
Loading