Skip to content

Commit

Permalink
git project sync UI (dup of existing ones for git sync)
Browse files Browse the repository at this point in the history
  • Loading branch information
gatzjames committed Jan 16, 2025
1 parent 41a8f56 commit f7cafc4
Show file tree
Hide file tree
Showing 12 changed files with 2,802 additions and 1 deletion.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ interface Props {
project: Project & { hasUncommittedOrUnpushedChanges?: boolean };
organizationId: string;
storage: ORG_STORAGE_RULE;
isGitSyncEnabled: boolean;
}

interface ProjectActionItem {
Expand All @@ -42,7 +43,7 @@ interface ProjectActionItem {
action: (projectId: string, projectName: string) => void;
}

export const ProjectDropdown: FC<Props> = ({ project, organizationId, storage }) => {
export const ProjectDropdown: FC<Props> = ({ project, organizationId, storage, isGitSyncEnabled }) => {
const [isProjectSettingsModalOpen, setIsProjectSettingsModalOpen] =
useState(false);
const deleteProjectFetcher = useFetcher();
Expand Down Expand Up @@ -244,6 +245,19 @@ export const ProjectDropdown: FC<Props> = ({ project, organizationId, storage })
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

Large diffs are not rendered by default.

128 changes: 128 additions & 0 deletions packages/insomnia/src/ui/components/modals/git-project-log-modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import React, { type FC, useEffect } from 'react';
import { Button, Cell, Column, Dialog, Heading, Modal, ModalOverlay, Row, Table, TableBody, TableHeader, Tooltip, TooltipTrigger } from 'react-aria-components';
import { useFetcher, useParams } from 'react-router-dom';

import type { GitLogLoaderData } from '../../routes/git-project-actions';
import { Icon } from '../icon';
import { TimeFromNow } from '../time-from-now';

interface Props {
onClose: () => void;
}

export const GitProjectLogModal: FC<Props> = ({ onClose }) => {
const { organizationId, projectId, workspaceId } = useParams() as {
organizationId: string;
projectId: string;
workspaceId: string;
};

const gitLogFetcher = useFetcher<GitLogLoaderData>();

const isLoading = gitLogFetcher.state !== 'idle';

useEffect(() => {
if (gitLogFetcher.state === 'idle' && !gitLogFetcher.data) {
// file://./../../routes/git-actions.tsx#gitLogLoader
gitLogFetcher.load(`/organization/${organizationId}/project/${projectId}/git/log`);
}
}, [organizationId, projectId, workspaceId, gitLogFetcher]);

const { log } = gitLogFetcher.data && 'log' in gitLogFetcher.data ? gitLogFetcher.data : { log: [] };

return (
<ModalOverlay
isOpen
onOpenChange={isOpen => {
!isOpen && onClose();
}}
isDismissable
className="w-full h-[--visual-viewport-height] fixed z-10 top-0 left-0 flex items-center justify-center bg-black/30"
>
<Modal
onOpenChange={isOpen => {
!isOpen && onClose();
}}
className="flex flex-col max-w-4xl w-full rounded-md border border-solid border-[--hl-sm] p-[--padding-lg] max-h-full bg-[--color-bg] text-[--color-font]"
>
<Dialog
className="outline-none flex-1 h-full flex flex-col overflow-hidden"
>
{({ close }) => (
<div className='flex-1 flex flex-col gap-4 overflow-hidden'>
<div className='flex gap-2 items-center justify-between'>
<Heading className='text-2xl'>History</Heading>
<Button
className="flex flex-shrink-0 items-center justify-center aspect-square h-6 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"
onPress={close}
>
<Icon icon="x" />
</Button>
</div>
<div className='rounded w-full border border-solid border-[--hl-sm] select-none overflow-y-auto max-h-96'>
<Table
selectionMode='multiple'
defaultSelectedKeys="all"
aria-label='Modified objects'
className="border-separate border-spacing-0 w-full"
>
<TableHeader>
<Column isRowHeader className="sticky px-2 py-2 top-0 z-10 border-b border-[--hl-sm] bg-[--hl-xs] text-left text-xs font-semibold backdrop-blur backdrop-filter focus:outline-none">
Message
</Column>
<Column className="sticky px-2 py-2 top-0 z-10 border-b border-[--hl-sm] bg-[--hl-xs] text-left text-xs font-semibold backdrop-blur backdrop-filter focus:outline-none">
When
</Column>
<Column className="sticky px-2 py-2 top-0 z-10 border-b border-[--hl-sm] bg-[--hl-xs] text-left text-xs font-semibold backdrop-blur backdrop-filter focus:outline-none">
Author
</Column>
</TableHeader>
<TableBody
renderEmptyState={() => (
<div className='p-2 text-center'>
{isLoading ? 'Loading...' : 'No history available'}
</div>
)}
className="divide divide-[--hl-sm] divide-solid"
items={log.map(logEntry => ({ id: logEntry.oid, ...logEntry }))}
>
{item => (
<Row className="group focus:outline-none focus-within:bg-[--hl-xxs] transition-colors">
<Cell className="whitespace-nowrap text-sm font-medium border-b border-solid border-[--hl-sm] group-last-of-type:border-none focus:outline-none">
<span className='p-2'>
{item.commit.message}
</span>
</Cell>
<Cell className="whitespace-nowrap text-sm font-medium border-b border-solid border-[--hl-sm] group-last-of-type:border-none focus:outline-none">
<TimeFromNow
className="no-wrap p-2"
timestamp={item.commit.author.timestamp * 1000}
intervalSeconds={30}
/>
</Cell>
<Cell className="whitespace-nowrap text-sm font-medium border-b border-solid border-[--hl-sm] group-last-of-type:border-none focus:outline-none">
<TooltipTrigger>
<Button className="p-2 h-full">
{item.commit.author.name}
</Button>
<Tooltip
placement="top end"
offset={8}
className="border select-none text-sm max-w-xs border-solid border-[--hl-sm] shadow-lg bg-[--color-bg] text-[--color-font] px-4 py-2 rounded-md overflow-y-auto max-h-[85vh] focus:outline-none"
>
{item.commit.author.email}
</Tooltip>
</TooltipTrigger>
</Cell>
</Row>
)}
</TableBody>
</Table>
</div>
</div>
)}
</Dialog>
</Modal>
</ModalOverlay>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import React, { type FunctionComponent } from 'react';

import { docsGitAccessToken } from '../../../../common/documentation';
import type { GitRepository } from '../../../../models/git-repository';
import { Link } from '../../base/link';
import { HelpTooltip } from '../../help-tooltip';

export interface Props {
gitRepository?: GitRepository | null;
onSubmit: (args: Partial<GitRepository>) => void;
}

export const CustomRepositorySettingsFormGroup: FunctionComponent<Props> = ({
gitRepository,
onSubmit,
}) => {
const linkIcon = <i className="fa fa-external-link-square" />;
const defaultValues = gitRepository || { uri: '', credentials: { username: '', token: '' }, author: { name: '', email: '' } };

const uri = defaultValues.uri;
const author = defaultValues.author;
const credentials = defaultValues?.credentials || { username: '', token: '' };

return (
<form
id="custom"
className='form-group'
onSubmit={event => {
event.preventDefault();
const formData = new FormData(event.currentTarget);
onSubmit({
uri: formData.get('uri') as string || '',
credentials: {
username: formData.get('username') as string || '',
token: formData.get('token') as string || '',
},
author: {
name: formData.get('authorName') as string || '',
email: formData.get('authorEmail') as string || '',
},
});
}}
>
<div className="form-control form-control--outlined">
<label>
Git URI (https, including .git suffix)
<input
type="url"
required
autoFocus
name="uri"
defaultValue={uri}
disabled={Boolean(uri)}
placeholder="https://github.com/org/repo.git"
/>
</label>
</div>
<div className="form-row">
<div className="form-control form-control--outlined">
<label>
Author Name
<input
required
type="text"
name="authorName"
placeholder="Name"
disabled={Boolean(uri)}
defaultValue={author.name}
/>
</label>
</div>
<div className="form-control form-control--outlined">
<label>
Author Email
<input
required
type="text"
name="authorEmail"
placeholder="Email"
disabled={Boolean(uri)}
defaultValue={author.email}
/>
</label>
</div>
</div>
<div className="form-row">
<div className="form-control form-control--outlined">
<label>
Username
<input
required
type="text"
name="username"
placeholder="MyUser"
disabled={Boolean(uri)}
defaultValue={credentials?.username}
/>
</label>
</div>
<div className="form-control form-control--outlined">
<label>
Authentication Token
<HelpTooltip className="space-left">
Create a personal access token
<br />
<Link href={docsGitAccessToken.github}>GitHub {linkIcon}</Link>
{' | '}
<Link href={docsGitAccessToken.gitlab}>GitLab {linkIcon}</Link>
{' | '}
<Link href={docsGitAccessToken.bitbucket}>Bitbucket {linkIcon}</Link>
{' | '}
<Link href={docsGitAccessToken.bitbucketServer}>
Bitbucket Server {linkIcon}
</Link>
{' | '}
<Link href={docsGitAccessToken.azureDevOps}>
Azure DevOps {linkIcon}
</Link>
</HelpTooltip>
<input
required
type="password"
name="token"
disabled={Boolean(uri)}
defaultValue={'token' in credentials ? credentials?.token : ''}
placeholder="88e7ee63b254e4b0bf047559eafe86ba9dd49507"
/>
</label>
</div>
</div>
</form>
);
};
Loading

0 comments on commit f7cafc4

Please sign in to comment.