Skip to content

Commit

Permalink
feat(#27): add option to include directories from another collection
Browse files Browse the repository at this point in the history
  • Loading branch information
notmedia committed Dec 4, 2022
1 parent 9b37104 commit f25cef4
Show file tree
Hide file tree
Showing 11 changed files with 451 additions and 94 deletions.
174 changes: 174 additions & 0 deletions src/app/pages/collections/forms/collection.form copy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import { faPlus, faTrash } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Button, Container, Input, Spacer, styled, Table, Text } from '@nextui-org/react';
import { nanoid } from 'nanoid';
import React from 'react';
import { Controller, useForm } from 'react-hook-form';

import { EzyButton, FileInput } from '@components';
import { Collection, CollectionType } from '@storage';

export interface CollectionFormProps {
id?: string;

defaultValues?: Partial<Collection<CollectionType>>;

onSubmit: (payload: Collection<CollectionType>) => void;
}

const PathComponent = styled(Text, {
overflowX: 'auto',
overflowY: 'hidden',
flex: 1,
});

type IncludeDirectoriesContainerProps = {
value?: string[];

onChange: (value: string[]) => void;
};

const IncludeDirectoriesContainer = React.forwardRef<
HTMLDivElement,
IncludeDirectoriesContainerProps
>(({ onChange, value = [] }, ref) => {
const [directories, setDirectories] = React.useState<string[]>(value);
const handleAddPathButtonClick = async () => {
const paths = await window.electronDialog.open({ properties: ['openDirectory'] });
const newDirectories = [...directories, ...paths];

setDirectories(newDirectories);
onChange(newDirectories);
};

const handleDeletePathButtonClick = (path: string) => () => {
const newDirectories = directories.filter((item) => item !== path);

setDirectories(newDirectories);
onChange(newDirectories);
};

return (
<div ref={ref}>
<div style={{ display: 'flex', alignItems: 'center' }}>
<Text weight="normal" size={14} css={{ userSelect: 'none', paddingLeft: 4 }}>
Include directories
</Text>
<Spacer x={0.5} />
<EzyButton
size="xs"
bordered
borderWeight="light"
icon={<FontAwesomeIcon size="sm" icon={faPlus} />}
css={{ minWidth: 10, color: '$ezy', borderColor: '$accents3' }}
onClick={handleAddPathButtonClick}
/>
</div>
<Spacer y={0.3} />
<Table
bordered
borderWeight="light"
fixed
selectionMode="single"
color="primary"
aria-label="include-directories-table"
>
<Table.Header>
<Table.Column>Path</Table.Column>
</Table.Header>
<Table.Body>
{directories.map((directory) => (
<Table.Row key={nanoid()}>
<Table.Cell css={{ display: 'flex', alignItems: 'center' }}>
<PathComponent small>{directory}</PathComponent>
<Spacer y={0} />
<Button
size="xs"
bordered
borderWeight="light"
color="error"
icon={<FontAwesomeIcon icon={faTrash} />}
css={{ marginLeft: 'auto', minWidth: 10 }}
onClick={handleDeletePathButtonClick(directory)}
/>
</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table>
</div>
);
});

export const CollectionForm: React.FC<CollectionFormProps> = ({
onSubmit = () => {},
id,
defaultValues,
}) => {
const {
control,
register,
reset,
handleSubmit,
formState: { errors },
} = useForm<Collection<CollectionType>>({ defaultValues });

React.useEffect(() => {
reset();
}, [defaultValues]);

return (
<form id={id} onSubmit={handleSubmit(onSubmit)}>
<Container
gap={0}
display="flex"
direction="column"
wrap="nowrap"
css={{
overflow: 'hidden',
paddingLeft: 1,
paddingRight: 1,
}}
>
<Input
autoFocus
bordered
borderWeight="light"
size="sm"
animated={false}
label="Name"
clearable
color={errors.name ? 'error' : 'default'}
{...register('name', { required: true })}
/>
<Spacer />
<Controller
name="options.path"
control={control}
rules={{
required: true,
}}
render={({ field }) => (
<FileInput
bordered
borderWeight="light"
buttonColor="default"
size="sm"
animated={false}
label="Protobuf path"
accept=".proto"
color={errors.options?.path ? 'error' : 'default'}
{...field}
/>
)}
/>
<Spacer />
<Controller
name="options.includeDirs"
control={control}
render={({ field }) => <IncludeDirectoriesContainer {...field} />}
/>
</Container>
</form>
);
};
95 changes: 5 additions & 90 deletions src/app/pages/collections/forms/collection.form.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { faPlus, faTrash } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Button, Container, Input, Spacer, styled, Table, Text } from '@nextui-org/react';
import { nanoid } from 'nanoid';
import { Container, Input, Spacer } from '@nextui-org/react';
import React from 'react';
import { Controller, useForm } from 'react-hook-form';

import { EzyButton, FileInput } from '@components';
import { FileInput } from '@components';
import { Collection, CollectionType } from '@storage';

import { IncludeDirectoriesField } from './fields';

export interface CollectionFormProps {
id?: string;

Expand All @@ -16,90 +15,6 @@ export interface CollectionFormProps {
onSubmit: (payload: Collection<CollectionType>) => void;
}

const PathComponent = styled(Text, {
overflowX: 'auto',
overflowY: 'hidden',
flex: 1,
});

type IncludeDirectoriesContainerProps = {
value?: string[];

onChange: (value: string[]) => void;
};

const IncludeDirectoriesContainer = React.forwardRef<
HTMLDivElement,
IncludeDirectoriesContainerProps
>(({ onChange, value = [] }, ref) => {
const [directories, setDirectories] = React.useState<string[]>(value);
const handleAddPathButtonClick = async () => {
const paths = await window.electronDialog.open({ properties: ['openDirectory'] });
const newDirectories = [...directories, ...paths];

setDirectories(newDirectories);
onChange(newDirectories);
};

const handleDeletePathButtonClick = (path: string) => () => {
const newDirectories = directories.filter((item) => item !== path);

setDirectories(newDirectories);
onChange(newDirectories);
};

return (
<div ref={ref}>
<div style={{ display: 'flex', alignItems: 'center' }}>
<Text weight="normal" size={14} css={{ userSelect: 'none', paddingLeft: 4 }}>
Include directories
</Text>
<Spacer x={0.5} />
<EzyButton
size="xs"
bordered
borderWeight="light"
icon={<FontAwesomeIcon size="sm" icon={faPlus} />}
css={{ minWidth: 10, color: '$ezy', borderColor: '$accents3' }}
onClick={handleAddPathButtonClick}
/>
</div>
<Spacer y={0.3} />
<Table
bordered
borderWeight="light"
fixed
selectionMode="single"
color="primary"
aria-label="include-directories-table"
>
<Table.Header>
<Table.Column>Path</Table.Column>
</Table.Header>
<Table.Body>
{directories.map((directory) => (
<Table.Row key={nanoid()}>
<Table.Cell css={{ display: 'flex', alignItems: 'center' }}>
<PathComponent small>{directory}</PathComponent>
<Spacer y={0} />
<Button
size="xs"
bordered
borderWeight="light"
color="error"
icon={<FontAwesomeIcon icon={faTrash} />}
css={{ marginLeft: 'auto', minWidth: 10 }}
onClick={handleDeletePathButtonClick(directory)}
/>
</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table>
</div>
);
});

export const CollectionForm: React.FC<CollectionFormProps> = ({
onSubmit = () => {},
id,
Expand Down Expand Up @@ -166,7 +81,7 @@ export const CollectionForm: React.FC<CollectionFormProps> = ({
<Controller
name="options.includeDirs"
control={control}
render={({ field }) => <IncludeDirectoriesContainer {...field} />}
render={({ field }) => <IncludeDirectoriesField {...field} />}
/>
</Container>
</form>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { faTrash } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Button, Container, Row, Text } from '@nextui-org/react';
import React from 'react';

import { TreeData, TreeNode, TreeNodeRendererProps } from '@components';

export type DirectoryNodeData = TreeData & {
value: string;
};

export const DirectoryNode: React.FC<
TreeNodeRendererProps<DirectoryNodeData> & { onDirectoryRemove: (id: string) => void }
> = ({ data, onDirectoryRemove }) => {
const content = (
<Container gap={0} fluid css={{ overflow: 'hidden' }}>
<Row gap={1} align="center" wrap="nowrap" css={{ whiteSpace: 'nowrap', userSelect: 'none' }}>
<Text size="$xs">{data.value}</Text>
</Row>
</Container>
);

const handleRemoveButtonClick = () => {
onDirectoryRemove(data.id);
};

const commandsContent = (
<Button
light
size="xs"
color="error"
css={{
float: 'right',
minWidth: 10,
color: '$accents9',
'&:hover': {
color: '$error',
backgroundColor: '$accents0',
},
}}
icon={<FontAwesomeIcon icon={faTrash} />}
onClick={handleRemoveButtonClick}
/>
);

return (
<TreeNode
id={data.id}
key={data.id}
content={content}
commandsContent={commandsContent}
defaultPadding
/>
);
};
Loading

0 comments on commit f25cef4

Please sign in to comment.