From ddb2395ef9ebe3aa1206dafd4a86c81dc59fa50a Mon Sep 17 00:00:00 2001 From: "munkhsaikhan.g@nmma.co" Date: Wed, 20 Sep 2023 13:50:28 +0800 Subject: [PATCH 01/50] clean timeclock --- .github/workflows/plugin-timeclock-api.yaml | 4 ++-- .github/workflows/plugin-timeclock-ui.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/plugin-timeclock-api.yaml b/.github/workflows/plugin-timeclock-api.yaml index 5c2df7ee74..d6f88d7084 100644 --- a/.github/workflows/plugin-timeclock-api.yaml +++ b/.github/workflows/plugin-timeclock-api.yaml @@ -62,5 +62,5 @@ jobs: run: | cd dist/plugin-timeclock-api/.erxes echo ${{ secrets.DOCKERHUB_TOKEN }} | docker login -u ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin - docker build -t erxes/plugin-timeclock-api:${GITHUB_REF#refs/heads/} -f Dockerfile . - docker push erxes/plugin-timeclock-api:${GITHUB_REF#refs/heads/} + docker build -t erxes/plugin-timeclock-api:community -f Dockerfile . + docker push erxes/plugin-timeclock-api:community diff --git a/.github/workflows/plugin-timeclock-ui.yaml b/.github/workflows/plugin-timeclock-ui.yaml index 9fc73399b0..cc982bb43b 100644 --- a/.github/workflows/plugin-timeclock-ui.yaml +++ b/.github/workflows/plugin-timeclock-ui.yaml @@ -84,4 +84,4 @@ jobs: tar -cf build.tar --directory=packages/plugin-timeclock-ui/.erxes/dist . cp build.tar packages/plugin-timeclock-ui/.erxes/dist rm -rf packages/plugin-timeclock-ui/.erxes/dist/*.js - aws s3 sync packages/plugin-timeclock-ui/.erxes/dist s3://erxes-${GITHUB_REF#refs/heads/}-plugins/uis/plugin-timeclock-ui --delete + aws s3 sync packages/plugin-timeclock-ui/.erxes/dist s3://erxes-community-plugins/uis/plugin-timeclock-ui --delete From 7fd22845fc8f4b7ae3c96c4a045bd16d0f7bbd47 Mon Sep 17 00:00:00 2001 From: "munkhsaikhan.g@nmma.co" Date: Wed, 20 Sep 2023 13:57:30 +0800 Subject: [PATCH 02/50] clean return clean; --- .github/workflows/plugin-timeclock-api.yaml | 4 ++-- .github/workflows/plugin-timeclock-ui.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/plugin-timeclock-api.yaml b/.github/workflows/plugin-timeclock-api.yaml index d6f88d7084..5c2df7ee74 100644 --- a/.github/workflows/plugin-timeclock-api.yaml +++ b/.github/workflows/plugin-timeclock-api.yaml @@ -62,5 +62,5 @@ jobs: run: | cd dist/plugin-timeclock-api/.erxes echo ${{ secrets.DOCKERHUB_TOKEN }} | docker login -u ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin - docker build -t erxes/plugin-timeclock-api:community -f Dockerfile . - docker push erxes/plugin-timeclock-api:community + docker build -t erxes/plugin-timeclock-api:${GITHUB_REF#refs/heads/} -f Dockerfile . + docker push erxes/plugin-timeclock-api:${GITHUB_REF#refs/heads/} diff --git a/.github/workflows/plugin-timeclock-ui.yaml b/.github/workflows/plugin-timeclock-ui.yaml index cc982bb43b..9fc73399b0 100644 --- a/.github/workflows/plugin-timeclock-ui.yaml +++ b/.github/workflows/plugin-timeclock-ui.yaml @@ -84,4 +84,4 @@ jobs: tar -cf build.tar --directory=packages/plugin-timeclock-ui/.erxes/dist . cp build.tar packages/plugin-timeclock-ui/.erxes/dist rm -rf packages/plugin-timeclock-ui/.erxes/dist/*.js - aws s3 sync packages/plugin-timeclock-ui/.erxes/dist s3://erxes-community-plugins/uis/plugin-timeclock-ui --delete + aws s3 sync packages/plugin-timeclock-ui/.erxes/dist s3://erxes-${GITHUB_REF#refs/heads/}-plugins/uis/plugin-timeclock-ui --delete From 4815ecf702cdb7b75459001ca4c836cd9078ca54 Mon Sep 17 00:00:00 2001 From: Anu-Ujin Bat-Ulzii Date: Wed, 20 Sep 2023 13:59:21 +0800 Subject: [PATCH 03/50] improve imap activity log --- .../src/components/ActivityLog.tsx | 17 +- packages/plugin-imap-ui/src/styles.ts | 434 ++++++++++++++++++ .../activityLogs/components/ActivityItem.tsx | 2 +- 3 files changed, 450 insertions(+), 3 deletions(-) create mode 100644 packages/plugin-imap-ui/src/styles.ts diff --git a/packages/plugin-imap-ui/src/components/ActivityLog.tsx b/packages/plugin-imap-ui/src/components/ActivityLog.tsx index c44f2fe545..ab72a8c0aa 100644 --- a/packages/plugin-imap-ui/src/components/ActivityLog.tsx +++ b/packages/plugin-imap-ui/src/components/ActivityLog.tsx @@ -1,4 +1,9 @@ +import { ActivityIcon, ActivityRow } from '../styles'; + +import Icon from '@erxes/ui/src/components/Icon'; import React from 'react'; +import Tip from '@erxes/ui/src/components/Tip'; +import { getIconAndColor } from '@erxes/ui-log/src/activityLogs/utils'; type Props = { contentType: string; @@ -12,8 +17,16 @@ class ActivityItem extends React.Component { const { contentTypeDetail } = activity; const { body, subject } = contentTypeDetail; + const iconAndColor = getIconAndColor('email'); + return ( - + + + + + + + Sent an email @@ -27,7 +40,7 @@ class ActivityItem extends React.Component { Content: - + ); } } diff --git a/packages/plugin-imap-ui/src/styles.ts b/packages/plugin-imap-ui/src/styles.ts new file mode 100644 index 0000000000..029a79e414 --- /dev/null +++ b/packages/plugin-imap-ui/src/styles.ts @@ -0,0 +1,434 @@ +import { colors, dimensions, typography } from '@erxes/ui/src/styles'; + +import { WhiteBox } from '@erxes/ui/src/layout/styles'; +import styled from 'styled-components'; +import styledTS from 'styled-components-ts'; + +const iconWrapperWidth = 80; + +const Timeline = styled.div` + padding-left: ${iconWrapperWidth}px; + position: relative; + + &:before { + border-right: 1px solid ${colors.borderDarker}; + content: ''; + height: 100%; + position: absolute; + z-index: 1; + margin-top: 1px; + left: ${iconWrapperWidth / 2}px; + } +`; + +const ActivityTitle = styled.h4` + margin: 0; + padding: ${dimensions.coreSpacing * 1.5}px 0 ${dimensions.coreSpacing}px; + font-weight: 400; + color: ${colors.textPrimary}; +`; + +const ActivityRow = styledTS<{ isConversation?: boolean }>(styled(WhiteBox))` + padding: ${props => (props.isConversation ? '0' : dimensions.coreSpacing)}px; + background: ${props => props.isConversation && colors.bgLight}; + position: relative; + overflow: visible; + margin-bottom: ${dimensions.coreSpacing}px; + border-radius: 2px; + height: auto; + transition:height 0.3s ease-out; + + &:last-of-type { + margin-bottom: 0; + } + + &:hover { + background: ${props => props.isConversation && colors.bgLightPurple}; + } +`; + +const FlexCenterContent = styled.div` + display: flex; + justify-content: space-between; + align-items: center; +`; + +const FlexContent = styled.div` + display: flex; + align-items: center; +`; + +const Title = styledTS<{ isComplete?: boolean; isEditing: boolean }>( + styled.div +)` + position: relative; + margin: ${dimensions.unitSpacing}px; + flex: 1; + font-size: 16px; + + > div { + margin-bottom: ${dimensions.unitSpacing}px; + } + + h4 { + text-decoration: ${props => props.isComplete && 'line-through'}; + transition: all ease 0.4s; + margin-bottom: ${dimensions.unitSpacing}px; + + > i { + margin-right: 5px; + } + } + + .icon-edit { + visibility: hidden; + transition: all ease 0.3s; + position: absolute; + right: ${dimensions.unitSpacing}px; + top: 5px; + } + + &:hover { + cursor: text; + + .icon-edit { + visibility: ${props => !props.isEditing && 'visible'}; + } + } +`; + +const FlexBody = styled.div` + flex: 1; + align-self: center; + word-break: break-word; + + p { + margin: 0; + font-weight: 500; + font-size: 14px; + } + + > div { + font-size: ${typography.fontSizeHeading8}px; + } + + span { + padding-right: ${dimensions.unitSpacing}px; + } +`; + +const Row = styled.div` + margin-right: ${dimensions.coreSpacing}px; +`; + +const AvatarWrapper = styledTS<{ + isOnline?: boolean; + hideIndicator?: boolean; + size?: number; +}>(styled.div)` + margin-right: ${dimensions.unitSpacing * 1.5}px; + position: relative; + max-height: ${props => (props.size ? `${props.size}px` : '50px')}; + + a { + float: none; + } + + &:before { + content: ''; + position: absolute; + right: -3px; + top: 32px; + background: ${props => + props.isOnline ? colors.colorCoreGreen : colors.colorShadowGray}; + width: 14px; + height: 14px; + border-radius: ${dimensions.unitSpacing}px; + font-size: ${dimensions.unitSpacing}px; + border: 1px solid ${colors.colorWhite}; + z-index: 1; + display: ${props => props.hideIndicator && 'none'}; + } +`; + +const ActivityIcon = styledTS<{ color?: string }>(styled.span)` + display: inline-block; + position: absolute; + background-color: ${props => props.color}; + height: ${iconWrapperWidth * 0.4}px; + width: ${iconWrapperWidth * 0.4}px; + line-height: ${iconWrapperWidth * 0.4}px; + text-align: center; + border-radius: 50%; + left: ${-iconWrapperWidth + iconWrapperWidth * 0.3}px; + top: ${dimensions.coreSpacing}px; + z-index: 2; + + & i { + margin: 0; + color: ${colors.colorWhite}; + } +`; + +const ActivityDate = styled.div` + color: ${colors.colorCoreGray}; + font-weight: ${typography.fontWeightLight}; + font-size: 11px; + margin-left: 5px; + cursor: help; +`; + +const ActivityContent = styledTS<{ isInternalNote?: boolean }>(styled.div)` + margin-top: ${dimensions.unitSpacing}px; + padding: ${dimensions.unitSpacing}px; + background: ${props => + props.isInternalNote ? colors.bgInternal : colors.borderPrimary}; + box-shadow: 0 1px 2px 0 ${colors.darkShadow}; + word-break:break-word; + + p:last-of-type { + margin-bottom: 0; + } + + img { + max-width: 100%; + } +`; + +const EmptyContent = styled.div` + display: flex; + height: 100%; + flex-direction: column; + align-items: center; + justify-content: center; + padding: ${dimensions.coreSpacing + dimensions.coreSpacing}px 0; + + > img { + width: 300px; + } + + p { + text-align: center; + max-width: 400px; + + b { + margin: ${dimensions.unitSpacing}px 0; + display: block; + } + } +`; + +const EmailContent = styledTS<{ longEmail: boolean; expand: boolean }>( + styled.div +)` + margin-top: ${dimensions.unitSpacing}px; + max-height: ${props => (props.expand ? 'auto' : '80px')}; + overflow: hidden; + transition: height .5s; + + p { + margin: 0; + } +`; + +const ExpandButton = styled.div` + margin-top: ${dimensions.coreSpacing}px; + cursor: pointer; + color: ${colors.colorCoreBlue}; + font-weight: 500; + transition: all ease 0.4s; + + &:hover { + text-decoration: underline; + } +`; + +const ContentShadow = styled.div` + background-image: linear-gradient(rgba(255, 255, 255, 0), rgb(255, 255, 255)); + background-size: 100% 30px; + height: 40px; + position: absolute; + bottom: 40px; + left: 0px; + right: 0px; +`; + +const Date = styledTS<{ showDetail?: boolean }>(styled.div)` + cursor: pointer; + display: table; + margin-right: ${dimensions.unitSpacing - 2}px; + line-height: 33px; + + span { + font-weight: 600; + color: ${colors.colorCoreBlue}; + } + + i { + margin-right: 5px; + + &:before { + transition: all .15s ease-in-out; + transform: ${props => props.showDetail && 'rotate(90deg)'}; + } + } +`; + +const Detail = styledTS<{ full?: boolean }>(styled.div)` + margin-top: ${props => + props.full ? dimensions.coreSpacing : dimensions.unitSpacing}px; + + > p { + margin: ${dimensions.unitSpacing}px 0 ${dimensions.coreSpacing}px; + } + `; + +const IconWrapper = styledTS<{ isComplete?: boolean }>(styled.div)` + cursor: pointer; + + > i { + background: ${props => + props.isComplete ? colors.colorCoreGreen : colors.bgLight}; + color: ${props => + props.isComplete ? colors.colorWhite : colors.colorShadowGray}; + border-radius: 25px; + display: inline-block; + line-height: 25px; + border: 2px solid ${props => + props.isComplete ? colors.colorCoreGreen : colors.colorShadowGray}; + transition: all ease 0.3s; + } +`; + +const Description = styled.div` + padding: ${dimensions.unitSpacing}px; + background: ${colors.bgLight}; + border: 1px solid ${colors.borderPrimary}; + border-radius: 2px; + margin: ${dimensions.coreSpacing}px 0; + word-break: break-word; +`; + +const DeleteAction = styled.div` + color: ${colors.colorCoreRed}; + padding-right: ${dimensions.unitSpacing}px; + cursor: pointer; + visibility: hidden; + transition: all 0.2s ease-in-out 0.2s; + font-weight: 500; +`; + +const JumpTo = styled(DeleteAction)` + color: ${colors.colorCoreBlue}; + margin-right: ${dimensions.unitSpacing}px; +`; + +const LogWrapper = styled.div` + flex: 1; + + &:hover { + ${DeleteAction} { + visibility: visible; + } + } +`; + +const ConversationContent = styled.div` + margin-top: ${dimensions.unitSpacing}px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 90%; +`; + +const Count = styled.div` + text-align: center; + border: 1px solid ${colors.colorShadowGray}; + border-radius: 2px; + padding: 0 7px; + color: ${colors.colorCoreGray}; +`; + +const Collapse = styled.div` + padding: ${dimensions.coreSpacing}px; + transition: all ease 0.5s; + + .dropdown { + display: none; + } +`; + +const CollapseTrigger = styled.div` + &:hover { + cursor: pointer; + opacity: 0.9; + } +`; + +const Header = styled(CollapseTrigger)` + border-bottom: 1px solid ${colors.colorShadowGray}; + padding-bottom: ${dimensions.unitSpacing}px; + margin-bottom: ${dimensions.coreSpacing}px; + font-size: 15px; +`; + +const CenterText = styled.div` + text-align: center; + margin-top: ${dimensions.coreSpacing}px; +`; + +const MergedContacts = styled.div` + a { + font-weight: 600; + + &:after { + content: ', '; + } + + &:last-child::after { + content: ''; + } + } +`; + +const ShowMore = styled.span` + color: #6569df; + cursor: pointer; + &:hover { + color: black; + } +`; + +export { + ShowMore, + Timeline, + ActivityTitle, + ActivityRow, + ActivityIcon, + AvatarWrapper, + ActivityDate, + ActivityContent, + Description, + EmailContent, + ConversationContent, + FlexCenterContent, + FlexContent, + FlexBody, + MergedContacts, + Row, + IconWrapper, + Title, + Date, + Detail, + ContentShadow, + Count, + LogWrapper, + Collapse, + Header, + CenterText, + ExpandButton, + DeleteAction, + JumpTo, + EmptyContent, + CollapseTrigger +}; diff --git a/packages/ui-log/src/activityLogs/components/ActivityItem.tsx b/packages/ui-log/src/activityLogs/components/ActivityItem.tsx index 3b928e5baa..1d724859d1 100644 --- a/packages/ui-log/src/activityLogs/components/ActivityItem.tsx +++ b/packages/ui-log/src/activityLogs/components/ActivityItem.tsx @@ -3,13 +3,13 @@ import { formatText, getIconAndColor } from '../utils'; import ErrorBoundary from '@erxes/ui/src/components/ErrorBoundary'; import { IActivityLog } from '../types'; +import { IIntegration } from '@erxes/ui-inbox/src/settings/integrations/types'; import { IUser } from '@erxes/ui/src/auth/types'; import Icon from '@erxes/ui/src/components/Icon'; import InternalNote from '../containers/items/InternalNote'; import React from 'react'; import { RenderDynamicComponent } from '@erxes/ui/src/utils/core'; import Tip from '@erxes/ui/src/components/Tip'; -import { IIntegration } from '@erxes/ui-inbox/src/settings/integrations/types'; type Props = { activity: IActivityLog; From b3e01a1d1c58a89be65ab2eb775342eded1c6eb0 Mon Sep 17 00:00:00 2001 From: Anu-Ujin Bat-Ulzii Date: Wed, 20 Sep 2023 18:00:47 +0800 Subject: [PATCH 04/50] update --- .../src/components/ActivityLog.tsx | 88 +++- packages/plugin-imap-ui/src/styles.ts | 401 ++---------------- .../activityLogs/components/Conversation.tsx | 11 +- .../activityLogs/components/ActivityItem.tsx | 2 +- packages/ui-log/src/activityLogs/styles.ts | 2 +- 5 files changed, 117 insertions(+), 387 deletions(-) diff --git a/packages/plugin-imap-ui/src/components/ActivityLog.tsx b/packages/plugin-imap-ui/src/components/ActivityLog.tsx index ab72a8c0aa..56fb74deca 100644 --- a/packages/plugin-imap-ui/src/components/ActivityLog.tsx +++ b/packages/plugin-imap-ui/src/components/ActivityLog.tsx @@ -1,8 +1,18 @@ -import { ActivityIcon, ActivityRow } from '../styles'; +import { + AcitivityHeader, + ActivityDate, + ActivityIcon, + ActivityRow, + IMapActivityContent, + SentWho +} from '../styles'; +import Button from '@erxes/ui/src/components/Button'; import Icon from '@erxes/ui/src/components/Icon'; import React from 'react'; import Tip from '@erxes/ui/src/components/Tip'; +import { __ } from '@erxes/ui/src/utils/core'; +import dayjs from 'dayjs'; import { getIconAndColor } from '@erxes/ui-log/src/activityLogs/utils'; type Props = { @@ -11,11 +21,62 @@ type Props = { currentUser: any; }; -class ActivityItem extends React.Component { +type State = { + shrink: boolean; +}; + +class ActivityItem extends React.Component { + constructor(props) { + super(props); + + const { contentTypeDetail = {} } = props.activity; + + this.state = { + shrink: (contentTypeDetail.body || '').length > 380 ? true : false + }; + } + + renderWhom(contentTypeDetail) { + const { from, to } = contentTypeDetail; + + const From = from ? from.map(f => f.name || f.address) : 'unknown'; + const To = to ? to.map(f => f.name || f.address) : 'unknown'; + + return ( + + {From.map(f => f)} + {__('send email to ')} + {To.map(t => t)} + + ); + } + + renderExpandButton() { + const { shrink } = this.state; + + if (!shrink) { + return null; + } + + return ( + this.setState({ shrink: !shrink })} + > + {shrink ? __('Expand email') : __('Shrink email')} + + ); + } + render() { const { activity } = this.props; - const { contentTypeDetail } = activity; - const { body, subject } = contentTypeDetail; + const { contentTypeDetail, contentType } = activity; + const { body, subject, createdAt } = contentTypeDetail; + + if (contentType && !contentType.includes('imap')) { + return null; + } const iconAndColor = getIconAndColor('email'); @@ -27,19 +88,16 @@ class ActivityItem extends React.Component { - - Sent an email - - - - Subject: - {subject} -
- Subject: -
- Content: + -
{description}
{(description || "").slice(0, 30) + "..."}
{description || ""}
$1' + ) + }} + /> + )} +
{item.primaryEmail}
$1' - ) - }} - /> - )} -
$1' + ) + }} + /> )} -
{primaryEmail}