diff --git a/datahub-web-react/src/app/entity/group/EditGroupDescriptionModal.tsx b/datahub-web-react/src/app/entity/group/EditGroupDescriptionModal.tsx
new file mode 100644
index 00000000000000..a898a73c254efe
--- /dev/null
+++ b/datahub-web-react/src/app/entity/group/EditGroupDescriptionModal.tsx
@@ -0,0 +1,64 @@
+import React, { useState } from 'react';
+import { Button, Modal, Form } from 'antd';
+import styled from 'styled-components';
+
+import { Editor } from '../shared/tabs/Documentation/components/editor/Editor';
+import { ANTD_GRAY } from '../shared/constants';
+
+type Props = {
+ onClose: () => void;
+ onSaveAboutMe: () => void;
+ setStagedDescription: (des: string) => void;
+ stagedDescription: string | undefined;
+};
+const StyledEditor = styled(Editor)`
+ border: 1px solid ${ANTD_GRAY[4]};
+`;
+
+export default function EditGroupDescriptionModal({
+ onClose,
+ onSaveAboutMe,
+ setStagedDescription,
+ stagedDescription,
+}: Props) {
+ const [form] = Form.useForm();
+ const [aboutText,setAboutText] = useState(stagedDescription)
+
+ function updateDescription(description: string) {
+ setAboutText(aboutText)
+ setStagedDescription(description);
+
+ }
+
+ const saveDescription = () => {
+ onSaveAboutMe();
+ onClose();
+ };
+
+ return (
+
+
+
+ >
+ }
+ >
+
+
+
+
+
+
+
+ );
+}
diff --git a/datahub-web-react/src/app/entity/group/GroupInfoSideBar.tsx b/datahub-web-react/src/app/entity/group/GroupInfoSideBar.tsx
index d9eaed2682ea19..07885a4d0f6304 100644
--- a/datahub-web-react/src/app/entity/group/GroupInfoSideBar.tsx
+++ b/datahub-web-react/src/app/entity/group/GroupInfoSideBar.tsx
@@ -16,14 +16,15 @@ import {
EmptyValue,
SocialDetails,
EditButton,
- AboutSection,
- AboutSectionText,
GroupsSection,
+ AboutSection,
} from '../shared/SidebarStyledComponents';
import GroupMembersSideBarSection from './GroupMembersSideBarSection';
import { useUserContext } from '../../context/useUserContext';
-
-const { Paragraph } = Typography;
+import StripMarkdownText, { removeMarkdown } from '../shared/components/styled/StripMarkdownText';
+import { Editor } from '../shared/tabs/Documentation/components/editor/Editor';
+import EditGroupDescriptionModal from './EditGroupDescriptionModal';
+import { REDESIGN_COLORS } from '../shared/constants';
type SideBarData = {
photoUrl: string | undefined;
@@ -80,6 +81,61 @@ const GroupTitle = styled(Typography.Title)`
}
`;
+const EditIcon = styled(EditOutlined)`
+ cursor: pointer;
+ color: ${REDESIGN_COLORS.BLUE};
+`;
+const AddNewDescription = styled(Button)`
+ display: none;
+ margin: -4px;
+ width: 140px;
+`;
+
+const StyledViewer = styled(Editor)`
+ padding-right: 8px;
+ display: block;
+
+ .remirror-editor.ProseMirror {
+ padding: 0;
+ }
+`;
+
+const DescriptionContainer = styled.div`
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ text-align:left;
+ font-weight: normal;
+ font
+ min-height: 22px;
+
+ &:hover ${AddNewDescription} {
+ display: block;
+ }
+ & ins.diff {
+ background-color: #b7eb8f99;
+ text-decoration: none;
+ &:hover {
+ background-color: #b7eb8faa;
+ }
+ }
+ & del.diff {
+ background-color: #ffa39e99;
+ text-decoration: line-through;
+ &: hover {
+ background-color: #ffa39eaa;
+ }
+ }
+`;
+
+const ExpandedActions = styled.div`
+ height: 10px;
+`;
+const ReadLessText = styled(Typography.Link)`
+ margin-right: 4px;
+`;
+
/**
* Responsible for reading & writing users.
*/
@@ -106,7 +162,17 @@ export default function GroupInfoSidebar({ sideBarData, refetch }: Props) {
const me = useUserContext();
const canEditGroup = me?.platformPrivileges?.manageIdentities;
const [groupTitle, setGroupTitle] = useState(name);
+ const [expanded, setExpanded] = useState(false);
+ const [isUpdatingDescription, SetIsUpdatingDescription] = useState(false);
+ const [stagedDescription, setStagedDescription] = useState(aboutText);
+
const [updateName] = useUpdateNameMutation();
+ const overLimit = removeMarkdown(aboutText || '').length > 80;
+ const ABBREVIATED_LIMIT = 80;
+
+ useEffect(() => {
+ setStagedDescription(aboutText);
+ }, [aboutText]);
useEffect(() => {
setGroupTitle(groupTitle);
@@ -136,12 +202,12 @@ export default function GroupInfoSidebar({ sideBarData, refetch }: Props) {
};
// About Text save
- const onSaveAboutMe = (inputString) => {
+ const onSaveAboutMe = () => {
updateCorpGroupPropertiesMutation({
variables: {
urn: urn || '',
input: {
- description: inputString,
+ description: stagedDescription,
},
},
})
@@ -201,16 +267,65 @@ export default function GroupInfoSidebar({ sideBarData, refetch }: Props) {
- {TITLES.about}
-
-
- {aboutText || }
-
-
+
+ {TITLES.about}
+
+ SetIsUpdatingDescription(true)} data-testid="edit-icon" />
+
+
+
+ {(aboutText && expanded) || !overLimit ? (
+ <>
+ {/* Read only viewer for displaying group description */}
+
+
+ {overLimit && (
+ {
+ setExpanded(false);
+ }}
+ >
+ Read Less
+
+ )}
+
+ >
+ ) : (
+ <>
+ {/* Display abbreviated description with option to read more */}
+
+ {
+ setExpanded(true);
+ }}
+ >
+ Read More
+
+ >
+ }
+ shouldWrap
+ >
+ {aboutText}
+
+ >
+ )}
+
+ {/* Modal for updating group description */}
+ {isUpdatingDescription && (
+ {
+ SetIsUpdatingDescription(false);
+ setStagedDescription(aboutText);
+ }}
+ onSaveAboutMe={onSaveAboutMe}
+ setStagedDescription={setStagedDescription}
+ stagedDescription={stagedDescription}
+ />
+ )}
diff --git a/datahub-web-react/src/app/identity/group/CreateGroupModal.tsx b/datahub-web-react/src/app/identity/group/CreateGroupModal.tsx
index 214cb251767c9c..4ba714ca23ae06 100644
--- a/datahub-web-react/src/app/identity/group/CreateGroupModal.tsx
+++ b/datahub-web-react/src/app/identity/group/CreateGroupModal.tsx
@@ -1,16 +1,23 @@
-import React, { useState } from 'react';
+import React, { useRef, useState } from 'react';
import { message, Button, Input, Modal, Typography, Form, Collapse } from 'antd';
+import styled from 'styled-components';
import { useCreateGroupMutation } from '../../../graphql/group.generated';
import { useEnterKeyListener } from '../../shared/useEnterKeyListener';
import { validateCustomUrnId } from '../../shared/textUtil';
import analytics, { EventType } from '../../analytics';
import { CorpGroup, EntityType } from '../../../types.generated';
+import { Editor as MarkdownEditor } from '../../entity/shared/tabs/Documentation/components/editor/Editor';
+import { ANTD_GRAY } from '../../entity/shared/constants';
type Props = {
onClose: () => void;
onCreate: (group: CorpGroup) => void;
};
+const StyledEditor = styled(MarkdownEditor)`
+ border: 1px solid ${ANTD_GRAY[4]};
+`;
+
export default function CreateGroupModal({ onClose, onCreate }: Props) {
const [stagedName, setStagedName] = useState('');
const [stagedDescription, setStagedDescription] = useState('');
@@ -19,45 +26,54 @@ export default function CreateGroupModal({ onClose, onCreate }: Props) {
const [createButtonEnabled, setCreateButtonEnabled] = useState(true);
const [form] = Form.useForm();
+ // Reference to the styled editor for handling focus
+ const styledEditorRef = useRef(null);
+
const onCreateGroup = () => {
- createGroupMutation({
- variables: {
- input: {
- id: stagedId,
- name: stagedName,
- description: stagedDescription,
- },
- },
- })
- .then(({ data, errors }) => {
- if (!errors) {
- analytics.event({
- type: EventType.CreateGroupEvent,
- });
- message.success({
- content: `Created group!`,
- duration: 3,
- });
- // TODO: Get a full corp group back from create endpoint.
- onCreate({
- urn: data?.createGroup || '',
- type: EntityType.CorpGroup,
+ // Check if the Enter key was pressed inside the styled editor to prevent unintended form submission
+ const isEditorNewlineKeypress =
+ document.activeElement !== styledEditorRef.current &&
+ !styledEditorRef.current?.contains(document.activeElement);
+ if (isEditorNewlineKeypress) {
+ createGroupMutation({
+ variables: {
+ input: {
+ id: stagedId,
name: stagedName,
- info: {
- description: stagedDescription,
- },
- });
- }
- })
- .catch((e) => {
- message.destroy();
- message.error({ content: `Failed to create group!: \n ${e.message || ''}`, duration: 3 });
+ description: stagedDescription,
+ },
+ },
})
- .finally(() => {
- setStagedName('');
- setStagedDescription('');
- });
- onClose();
+ .then(({ data, errors }) => {
+ if (!errors) {
+ analytics.event({
+ type: EventType.CreateGroupEvent,
+ });
+ message.success({
+ content: `Created group!`,
+ duration: 3,
+ });
+ // TODO: Get a full corp group back from create endpoint.
+ onCreate({
+ urn: data?.createGroup || '',
+ type: EntityType.CorpGroup,
+ name: stagedName,
+ info: {
+ description: stagedDescription,
+ },
+ });
+ }
+ })
+ .catch((e) => {
+ message.destroy();
+ message.error({ content: `Failed to create group!: \n ${e.message || ''}`, duration: 3 });
+ })
+ .finally(() => {
+ setStagedName('');
+ setStagedDescription('');
+ });
+ onClose();
+ }
};
// Handle the Enter press
@@ -65,8 +81,13 @@ export default function CreateGroupModal({ onClose, onCreate }: Props) {
querySelectorToExecuteClick: '#createGroupButton',
});
+ function updateDescription(description: string) {
+ setStagedDescription(description);
+ }
+
return (
Description}>
An optional description for your new group.
-
- setStagedDescription(event.target.value)}
- />
+
+ {/* Styled editor for the group description */}
+
+
+
diff --git a/smoke-test/tests/cypress/cypress/e2e/settings/managing_groups.js b/smoke-test/tests/cypress/cypress/e2e/settings/managing_groups.js
index 70219a550cd8bb..978a245c3d9e33 100644
--- a/smoke-test/tests/cypress/cypress/e2e/settings/managing_groups.js
+++ b/smoke-test/tests/cypress/cypress/e2e/settings/managing_groups.js
@@ -72,8 +72,10 @@ describe("create and manage group", () => {
cy.focused().clear().type(`Test group EDITED ${test_id}{enter}`);
cy.waitTextVisible("Name Updated");
cy.contains(`Test group EDITED ${test_id}`).should("be.visible");
- cy.contains("Test group description").find('[aria-label="edit"]').click();
- cy.focused().type(" EDITED{enter}");
+ cy.get('[data-testid="edit-icon"]').click();
+ cy.waitTextVisible("Edit Description");
+ cy.get("#description").should("be.visible").type(" EDITED");
+ cy.get("#updateGroupButton").click();
cy.waitTextVisible("Changes saved.");
cy.contains("Test group description EDITED").should("be.visible");
cy.clickOptionWithText("Add Owners");