Skip to content

Commit

Permalink
git repo sync dropdown ui
Browse files Browse the repository at this point in the history
  • Loading branch information
gatzjames committed Jan 16, 2025
1 parent f7cafc4 commit ab43586
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import { type FC } from 'react';
import React from 'react';
import { useRouteLoaderData } from 'react-router-dom';

import { isRemoteProject } from '../../../models/project';
import { isGitProject, isRemoteProject } from '../../../models/project';
import { useOrganizationPermissions } from '../../hooks/use-organization-features';
import { useRootLoaderData } from '../../routes/root';
import type { WorkspaceLoaderData } from '../../routes/workspace';
import { GitProjectSyncDropdown } from './git-project-sync-dropdown';
import { GitSyncDropdown } from './git-sync-dropdown';
import { SyncDropdown } from './sync-dropdown';

Expand Down Expand Up @@ -43,6 +44,10 @@ export const WorkspaceSyncDropdown: FC = () => {

const shouldShowGitSyncDropdown = features.gitSync.enabled && (activeWorkspaceMeta?.gitRepositoryId || !isRemoteProject(activeProject));
if (shouldShowGitSyncDropdown) {
if (isGitProject(activeProject)) {
return <GitProjectSyncDropdown gitRepository={gitRepository} />;
}

return <GitSyncDropdown isInsomniaSyncEnabled={isRemoteProject(activeProject)} gitRepository={gitRepository} />;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,10 @@ interface Props {
importFrom: () => void;
cloneFromGit: () => void;
isGitSyncEnabled: boolean;
isGitProject: boolean;
}

export const EmptyStatePane: FC<Props> = ({ createRequestCollection, createDesignDocument, createMockServer, createEnvironment, importFrom, cloneFromGit, isGitSyncEnabled }) => {
export const EmptyStatePane: FC<Props> = ({ createRequestCollection, createDesignDocument, createMockServer, createEnvironment, importFrom, cloneFromGit, isGitSyncEnabled, isGitProject }) => {
const { organizationId } = useParams<{ organizationId: string }>();
const { organizations } = useOrganizationLoaderData();
const { userSession } = useRootLoaderData();
Expand Down Expand Up @@ -207,7 +208,7 @@ export const EmptyStatePane: FC<Props> = ({ createRequestCollection, createDesig
}}
/> Clipboard
</AlmostSquareButton>
<AlmostSquareButton
{isGitProject ? null : <AlmostSquareButton
aria-label='Clone git repository'
data-test-git-enable={isGitSyncEnabled}
onClick={
Expand All @@ -224,7 +225,7 @@ export const EmptyStatePane: FC<Props> = ({ createRequestCollection, createDesig
fontSize: 'var(--font-size-lg)',
}}
/> Git Clone
</AlmostSquareButton>
</AlmostSquareButton>}
<AlmostSquareButton
onClick={importFrom}
>
Expand Down
135 changes: 90 additions & 45 deletions packages/insomnia/src/ui/routes/project.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,13 @@ import { descendingNumberSort, sortMethodMap } from '../../common/sorting';
import * as models from '../../models';
import { userSession } from '../../models';
import type { ApiSpec } from '../../models/api-spec';
import type { GitRepository } from '../../models/git-repository';
import { sortProjects } from '../../models/helpers/project';
import type { MockServer } from '../../models/mock-server';
import type { Organization } from '../../models/organization';
import { isOwnerOfOrganization, isPersonalOrganization, isScratchpadOrganizationId } from '../../models/organization';
import {
isGitProject,
isRemoteProject,
type Project,
SCRATCHPAD_PROJECT_ID,
Expand All @@ -76,6 +78,7 @@ import { insomniaFetch } from '../../ui/insomniaFetch';
import { invariant } from '../../utils/invariant';
import { getInitialRouteForOrganization } from '../../utils/router';
import { AvatarGroup } from '../components/avatar';
import { GitProjectSyncDropdown } from '../components/dropdowns/git-project-sync-dropdown';
import { ProjectDropdown } from '../components/dropdowns/project-dropdown';
import { WorkspaceCardDropdown } from '../components/dropdowns/workspace-card-dropdown';
import { ErrorBoundary } from '../components/error-boundary';
Expand Down Expand Up @@ -281,6 +284,7 @@ export interface ProjectLoaderData {
mockServersCount: number;
projectsCount: number;
activeProject?: Project;
activeProjectGitRepository?: GitRepository | null;
projects: Project[];
learningFeaturePromise?: Promise<LearningFeature>;
remoteFilesPromise?: Promise<InsomniaFile[]>;
Expand Down Expand Up @@ -548,6 +552,7 @@ export const loader: LoaderFunction = async ({
mockServersCount: 0,
projectsCount: 0,
activeProject: undefined,
activeProjectGitRepository: null,
projects: [],
};
}
Expand Down Expand Up @@ -576,13 +581,16 @@ export const loader: LoaderFunction = async ({

const projectsSyncStatusPromise = CheckAllProjectSyncStatus(projects);

const activeProjectGitRepository = isGitProject(project) ? await models.gitRepository.getById(project.gitRepositoryId || '') : null;

return defer({
localFiles,
learningFeaturePromise,
remoteFilesPromise,
projects,
projectsCount: organizationProjects.length,
activeProject: project,
activeProjectGitRepository,
allFilesCount: localFiles.length,
environmentsCount: localFiles.filter(
file => file.scope === 'environment'
Expand All @@ -604,6 +612,7 @@ const ProjectRoute: FC = () => {
const {
localFiles,
activeProject,
activeProjectGitRepository,
projects,
allFilesCount,
environmentsCount,
Expand Down Expand Up @@ -929,12 +938,17 @@ const ProjectRoute: FC = () => {
icon: 'code',
action: createNewGlobalEnvironment,
},
{
...activeProject && isGitProject(activeProject) ? [] : [{
id: 'git-clone',
name: 'Git Clone',
icon: 'code-fork',
action: importFromGit,
},
}] satisfies {
id: string;
name: string;
icon: IconName;
action: () => void;
}[],
];

const scopeActionList: {
Expand Down Expand Up @@ -1131,7 +1145,7 @@ const ProjectRoute: FC = () => {
<span className="group-aria-selected:bg-[--color-surprise] transition-colors top-0 left-0 absolute h-full w-[2px] bg-transparent" />
<Icon
icon={
isRemoteProject(item) ? 'globe-americas' : 'laptop'
isRemoteProject(item) ? 'globe-americas' : isGitProject(item) ? ['fab', 'git-alt'] : 'laptop'
}
/>
<span className={'truncate'}>{item.name}</span>
Expand All @@ -1148,6 +1162,7 @@ const ProjectRoute: FC = () => {
organizationId={organizationId}
project={item}
storage={storage}
isGitSyncEnabled={isGitSyncEnabled}
/>
)}
</div>
Expand All @@ -1157,49 +1172,52 @@ const ProjectRoute: FC = () => {
</GridList>
</div>
{activeProject && (
<GridList
aria-label="Scope filter"
items={scopeActionList}
className="overflow-y-auto flex-shrink-0 flex-1 data-[empty]:py-0 py-[--padding-sm]"
disallowEmptySelection
selectedKeys={[workspaceListScope || 'all']}
selectionMode="single"
onSelectionChange={keys => {
if (keys !== 'all') {
const [value] = keys.values();

setWorkspaceListScope(value.toString());
}
}}
>
{item => {
return (
<GridListItem textValue={item.label} className="group outline-none select-none">
<div
className="flex select-none outline-none group-aria-selected:text-[--color-font] relative group-aria-selected:bg-[--hl-sm] group-hover:bg-[--hl-xs] group-focus:bg-[--hl-sm] transition-colors gap-2 px-4 items-center h-12 w-full overflow-hidden text-[--hl]"
>
<span className='w-6 h-6 flex items-center justify-center'>
<Icon icon={item.icon} className='w-6' />
</span>
<>
<GridList
aria-label="Scope filter"
items={scopeActionList}
className="overflow-y-auto flex-shrink-0 flex-1 data-[empty]:py-0 py-[--padding-sm]"
disallowEmptySelection
selectedKeys={[workspaceListScope || 'all']}
selectionMode="single"
onSelectionChange={keys => {
if (keys !== 'all') {
const [value] = keys.values();

setWorkspaceListScope(value.toString());
}
}}
>
{item => {
return (
<GridListItem textValue={item.label} className="group outline-none select-none">
<div
className="flex select-none outline-none group-aria-selected:text-[--color-font] relative group-aria-selected:bg-[--hl-sm] group-hover:bg-[--hl-xs] group-focus:bg-[--hl-sm] transition-colors gap-2 px-4 items-center h-12 w-full overflow-hidden text-[--hl]"
>
<span className='w-6 h-6 flex items-center justify-center'>
<Icon icon={item.icon} className='w-6' />
</span>

<span className="truncate capitalize">
{item.label}
</span>
<span className="flex-1" />
{item.action && (
<Button
onPress={item.action.run}
aria-label={item.action.label}
className="opacity-80 items-center hover:opacity-100 focus:opacity-100 data-[pressed]:opacity-100 flex group-focus:opacity-100 group-hover:opacity-100 justify-center h-6 aspect-square aria-pressed:bg-[--hl-sm] rounded-sm text-[--color-font] hover:bg-[--hl-xs] focus:ring-inset ring-1 ring-transparent focus:ring-[--hl-md] transition-all text-sm"
>
<Icon icon={item.action.icon} />
</Button>
)}
</div>
</GridListItem>
);
}}
</GridList>
<span className="truncate capitalize">
{item.label}
</span>
<span className="flex-1" />
{item.action && (
<Button
onPress={item.action.run}
aria-label={item.action.label}
className="opacity-80 items-center hover:opacity-100 focus:opacity-100 data-[pressed]:opacity-100 flex group-focus:opacity-100 group-hover:opacity-100 justify-center h-6 aspect-square aria-pressed:bg-[--hl-sm] rounded-sm text-[--color-font] hover:bg-[--hl-xs] focus:ring-inset ring-1 ring-transparent focus:ring-[--hl-md] transition-all text-sm"
>
<Icon icon={item.action.icon} />
</Button>
)}
</div>
</GridListItem>
);
}}
</GridList>
{isGitProject(activeProject) && <GitProjectSyncDropdown gitRepository={activeProjectGitRepository || null} />}
</>
)}
{!isLearningFeatureDismissed && learningFeature?.active && (
<div className='flex flex-shrink-0 flex-col gap-2 p-[--padding-sm]'>
Expand Down Expand Up @@ -1411,6 +1429,7 @@ const ProjectRoute: FC = () => {
importFrom={() => setImportModalType('file')}
cloneFromGit={importFromGit}
isGitSyncEnabled={isGitSyncEnabled}
isGitProject={isGitProject(activeProject)}
/>
);
}}
Expand Down Expand Up @@ -1592,6 +1611,19 @@ const ProjectRoute: FC = () => {
Project type
</Label>
<div className="flex gap-2">
<Radio
isDisabled={!isGitSyncEnabled}
value="git"
className="flex-1 data-[selected]:border-[--color-surprise] data-[selected]:ring-2 data-[selected]:ring-[--color-surprise] data-[disabled]:opacity-25 hover:bg-[--hl-xs] focus:bg-[--hl-sm] border border-solid border-[--hl-md] rounded p-4 focus:outline-none transition-colors"
>
<div className='flex items-center gap-2'>
<Icon icon={['fab', 'git-alt']} />
<Heading className="text-lg font-bold">Git Sync</Heading>
</div>
<p className='pt-2'>
Stored locally and synced to a Git repository. Ideal for version control and collaboration.
</p>
</Radio>
<Radio
isDisabled={storage === ORG_STORAGE_RULE.LOCAL_ONLY}
value="remote"
Expand Down Expand Up @@ -1728,6 +1760,19 @@ const ProjectRoute: FC = () => {
Project type
</Label>
<div className="flex gap-2">
<Radio
isDisabled={!isGitSyncEnabled}
value="git"
className="data-[selected]:border-[--color-surprise] flex-1 data-[disabled]:opacity-25 data-[selected]:ring-2 data-[selected]:ring-[--color-surprise] hover:bg-[--hl-xs] focus:bg-[--hl-sm] border border-solid border-[--hl-md] rounded p-4 focus:outline-none transition-colors"
>
<div className='flex items-center gap-2'>
<Icon icon={['fab', 'git-alt']} />
<Heading className="text-lg font-bold">Git Sync</Heading>
</div>
<p className='pt-2'>
Stored locally and synced with Git for version control.
</p>
</Radio>
<Radio
isDisabled={storage === ORG_STORAGE_RULE.LOCAL_ONLY}
value="remote"
Expand Down
5 changes: 3 additions & 2 deletions packages/insomnia/src/ui/routes/workspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import type { GrpcRequest } from '../../models/grpc-request';
import type { GrpcRequestMeta } from '../../models/grpc-request-meta';
import { sortProjects } from '../../models/helpers/project';
import type { MockServer } from '../../models/mock-server';
import type { Project } from '../../models/project';
import { isGitProject, type Project } from '../../models/project';
import type { Request } from '../../models/request';
import { isRequestGroup, type RequestGroup } from '../../models/request-group';
import type { RequestGroupMeta } from '../../models/request-group-meta';
Expand Down Expand Up @@ -89,8 +89,9 @@ export const workspaceLoader: LoaderFunction = async ({
workspaceId,
);
invariant(activeWorkspaceMeta, 'Workspace meta not found');
const gitRepositoryId = isGitProject(activeProject) ? activeProject.gitRepositoryId : activeWorkspaceMeta.gitRepositoryId;
const gitRepository = await models.gitRepository.getById(
activeWorkspaceMeta.gitRepositoryId || '',
gitRepositoryId || '',
);

const baseEnvironment = await models.environment.getByParentId(workspaceId);
Expand Down

0 comments on commit ab43586

Please sign in to comment.