Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Contextual data for auto cluster and summarization #2959

Merged
merged 1 commit into from
Jun 13, 2024
Merged
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
212 changes: 212 additions & 0 deletions app/components/TagInput/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
import React, { useState, useCallback } from 'react';
import { _cs } from '@togglecorp/fujs';
import {
IoClose,
IoCheckmarkSharp,
IoAdd,
} from 'react-icons/io5';
import {
Button,
RawInput,
List,
Tag,
TagProps as PropsFromTag,
useBooleanState,
} from '@the-deep/deep-ui';

import styles from './styles.css';

type TagVariant = PropsFromTag['variant'];

interface TagProps extends PropsFromTag {
label: string;
onRemove: (key: string) => void;
variant?: TagVariant;
disabled?: boolean;
readOnly?: boolean;
className?: string;
}

function ModifiedTag(props: TagProps) {
const {
className,
onRemove,
label,
variant,
disabled,
readOnly,
...otherProps
} = props;

return (
<Tag
className={_cs(className, styles.tag)}
actions={!readOnly && (
<Button
name={label}
onClick={onRemove}
className={styles.tagButton}
childrenContainerClassName={styles.children}
disabled={disabled}
icons={(
<IoClose />
)}
/>
)}
variant={variant}
{...otherProps}
>
{label}
</Tag>
);
}

const keySelector = (d: string) => d;
const emptyValue: string[] = [];

interface Props<N extends string> extends PropsFromTag{
className?: string;
tagClassName?: string;
value?: string[];
label: string;
name: N;
variant?: TagVariant;
onChange?: (newVal: string[], name: N) => void;
disabled?: boolean;
readOnly?: boolean;
}

function TagInput<N extends string>(props: Props<N>) {
const {
className,
value = emptyValue,
onChange,
name,
label,
variant,
disabled,
readOnly,
tagClassName,
...otherProps
} = props;

const [newTagValue, setNewTagValue] = useState<string | undefined>();
const [newTagAddShown, showNewTagAdd, hideNewTagAdd] = useBooleanState(false);

const handleTagAdd = useCallback(() => {
if (!newTagValue) {
setNewTagValue(undefined);
hideNewTagAdd();
return;
}

const indexToRemove = value.indexOf(newTagValue);
if (indexToRemove === -1) {
const newValues = [...value];
newValues.push(newTagValue);
if (onChange) {
onChange(newValues, name);
}
}
setNewTagValue(undefined);
hideNewTagAdd();
}, [onChange, value, name, hideNewTagAdd, newTagValue]);

const handleTagRemove = useCallback((tagToRemove: string) => {
const indexToRemove = value.indexOf(tagToRemove);
if (indexToRemove !== -1) {
const newValues = [...value];
newValues.splice(indexToRemove, 1);
if (onChange) {
onChange(newValues, name);
}
}
}, [onChange, value, name]);

const tagRendererParams = useCallback(
(d: string) => ({
label: d,
onRemove: handleTagRemove,
variant,
disabled,
readOnly,
className: tagClassName,
...otherProps,
}),
[handleTagRemove, variant, readOnly, disabled, tagClassName, otherProps],
);

const handleNewTagAddCancel = useCallback(() => {
setNewTagValue(undefined);
hideNewTagAdd();
}, [hideNewTagAdd]);

return (
<div className={_cs(styles.tagInput, className)}>
<div className={styles.label}>
{label}
</div>
<div className={styles.tags}>
<List
data={value}
rendererParams={tagRendererParams}
renderer={ModifiedTag}
keySelector={keySelector}
/>
{!readOnly && (
<Tag
className={styles.tag}
actionsContainerClassName={styles.tagActions}
actions={newTagAddShown ? (
<>
<Button
name="done"
onClick={handleTagAdd}
className={_cs(styles.tagButton, styles.checkButton)}
childrenContainerClassName={styles.children}
disabled={disabled}
icons={(
<IoCheckmarkSharp />
)}
/>
<Button
name="remove"
onClick={handleNewTagAddCancel}
className={_cs(styles.tagButton, styles.cancelButton)}
childrenContainerClassName={styles.children}
disabled={disabled}
icons={(
<IoClose />
)}
/>
</>
) : (
<Button
name="add"
onClick={showNewTagAdd}
className={styles.tagButton}
childrenContainerClassName={styles.children}
disabled={disabled}
icons={(
<IoAdd />
)}
/>
)}
>
{newTagAddShown ? (
<RawInput
name="newTag"
value={newTagValue}
onChange={setNewTagValue}
autoFocus
disabled={disabled}
/>
) : ''}
</Tag>
)}
</div>
</div>
);
}

export default TagInput;
45 changes: 45 additions & 0 deletions app/components/TagInput/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
.tag-input {
.tag-button {
--padding: var(--dui-spacing-extra-small);
border: none;
border-radius: calc(1em + var(--padding) / 2);
background-color: transparent;
padding: var(--padding);
width: calc(1em + 2 * var(--padding));
height: calc(1em + 2 * var(--padding));
color: inherit;

.children {
padding: 0;
}

&.check-button {
color: var(--dui-color-success);
}

&.cancel-button {
color: var(--dui-color-danger);
}
}

.label {
padding: var(--dui-spacing-small) var(--dui-spacing-medium);
color: var(--dui-color-text-label);
font-size: var(--dui-font-size-small);
font-weight: var(--dui-font-weight-bold);
}

.tags {
display: flex;
flex-wrap: wrap;

.tag {
margin: var(--dui-spacing-extra-small);
}

.tag-actions {
display: flex;
align-items: center;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react';

import {
Modal,
Button,
} from '@the-deep/deep-ui';

import TagInput from '#components/TagInput';

interface Props {
widgetTags: string[];
setWidgetTags: React.Dispatch<React.SetStateAction<string[] | undefined>>;
handleSubmitButtonClick: () => void;
onCloseButtonClick: () => void;
}

function SummaryTagsModal(props: Props) {
const {
widgetTags,
setWidgetTags,
handleSubmitButtonClick,
onCloseButtonClick,
} = props;

return (
<Modal
heading="Automatic Summary"
onCloseButtonClick={onCloseButtonClick}
footerActions={(
<Button
name={undefined}
onClick={handleSubmitButtonClick}
>
Submit tags
</Button>
)}
>
Please select/add relevant tags to get better summary.

<TagInput
name="tags"
label="Tags"
value={widgetTags}
onChange={setWidgetTags}
/>
</Modal>
);
}

export default SummaryTagsModal;
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,31 @@ import React, {
} from 'react';
import {
Button,
CollapsibleContainer,
Container,
ListView,
useConfirmation,
Modal,
QuickActionButton,
CollapsibleContainer,
SegmentInput,
Tab,
TabList,
TabPanel,
Tabs,
TextInput,
Tooltip,
useConfirmation,
} from '@the-deep/deep-ui';
import { isDefined, encodeDate, _cs, unique, listToGroupList } from '@togglecorp/fujs';
import {
isDefined,
encodeDate,
_cs,
unique,
listToGroupList,
} from '@togglecorp/fujs';
import {
IoChevronForward,
IoChevronBackOutline,
IoInformation,
} from 'react-icons/io5';
import { VscServerProcess } from 'react-icons/vsc';

Expand Down Expand Up @@ -385,6 +393,16 @@ function StoryAnalysisModal(props: Props) {
>
Automatic Summary
</Tab>
{project?.isPrivate && (
<div className={styles.info}>
<IoInformation />
<Tooltip>
Auto summary is not available
for private projects to
maintain document privacy.
</Tooltip>
</div>
)}
</TabList>
)}
contentClassName={styles.tabPanelContainer}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@
font-size: var(--dui-font-size-large);
font-weight: var(--dui-font-weight-regular);
}
.info {
display: flex;
align-self: center;
border: var(--dui-width-separator-thin) solid var(--dui-color-separator);
border-radius: 50%;
padding: var(--dui-spacing-extra-small);
font-size: var(--dui-font-size-medium);
}

.brain-icon {
align-self: center;
}

.tab-panel-container {
display: flex;
Expand Down
Loading
Loading