From fe250b103e750d09a437fb3483a548a9ee4bea56 Mon Sep 17 00:00:00 2001 From: jankyzhang Date: Fri, 20 Sep 2019 04:15:15 +0800 Subject: [PATCH 1/6] bug #3273 Show Created By for files and links list in Assets Library --- .../AssetsLibrary/FilesGridView.jsx | 14 +++++++ src/components/AssetsLibrary/GridView.scss | 2 +- .../AssetsLibrary/LinksGridView.jsx | 15 ++++++++ src/components/AssetsLibrary/SubFolder.jsx | 17 ++++++++- .../detail/containers/AssetsInfoContainer.jsx | 38 ++++++++++++++----- 5 files changed, 74 insertions(+), 12 deletions(-) diff --git a/src/components/AssetsLibrary/FilesGridView.jsx b/src/components/AssetsLibrary/FilesGridView.jsx index 2618fab04..0b9a6bcd5 100644 --- a/src/components/AssetsLibrary/FilesGridView.jsx +++ b/src/components/AssetsLibrary/FilesGridView.jsx @@ -10,6 +10,7 @@ import DeleteFileLinkModal from '../LinksMenu/DeleteFileLinkModal' import EditFileAttachment from '../LinksMenu/EditFileAttachment' import SubFolder from './SubFolder' import ItemOperations from './ItemOperations' +import UserTooltip from '../User/UserTooltip' import FolderIcon from '../../assets/icons/v.2.5/icon-folder-small.svg' @@ -78,6 +79,7 @@ const FilesGridView = ({ link={ subFolderContent } renderLink={ renderLink } goBack={goBack} + projectMembers={projectMembers} onDeletePostAttachment={onDeletePostAttachment} loggedInUser={loggedInUser} formatModifyDate={formatModifyDate} @@ -99,6 +101,7 @@ const FilesGridView = ({
  • Type
    Name
    +
    Created By
    Modified
  • @@ -119,12 +122,14 @@ const FilesGridView = ({ const canEdit = `${link.createdBy}` === `${loggedInUser.userId}` const changeSubFolder = () => onChangeSubFolder(link) + const owner = _.find(projectMembers, m => m.userId === _.parseInt(link.createdBy)) if (Array.isArray(link.children) && link.children.length > 0) { return (
  • {formatFolderTitle(link.title)}

    +
    {formatModifyDate(link)}
  • ) @@ -161,6 +166,15 @@ const FilesGridView = ({

    {renderLink(link)}

    +
    + {!owner && (
    Unknown
    )} + {owner && ( +
    +
    + +
    +
    )} +
    {formatModifyDate(link)}
    {canEdit && ( diff --git a/src/components/AssetsLibrary/GridView.scss b/src/components/AssetsLibrary/GridView.scss index 7ab34c62b..bad510657 100644 --- a/src/components/AssetsLibrary/GridView.scss +++ b/src/components/AssetsLibrary/GridView.scss @@ -85,7 +85,7 @@ } } -.item-modified { +.item-modified, .item-created-by { -webkit-box-flex: 0; -ms-flex: none; flex: none; diff --git a/src/components/AssetsLibrary/LinksGridView.jsx b/src/components/AssetsLibrary/LinksGridView.jsx index 25fd4b45d..33f23afa3 100644 --- a/src/components/AssetsLibrary/LinksGridView.jsx +++ b/src/components/AssetsLibrary/LinksGridView.jsx @@ -8,6 +8,7 @@ import DeleteLinkModal from '../LinksMenu/DeleteLinkModal' import EditLinkModal from '../LinksMenu/EditLinkModal' import SubFolder from './SubFolder' import ItemOperations from './ItemOperations' +import UserTooltip from '../User/UserTooltip' import FolderIcon from '../../assets/icons/v.2.5/icon-folder-small.svg' import LinkIcon from '../../assets/icons/link-12.svg' @@ -28,6 +29,7 @@ const LinksGridView = ({ title, formatModifyDate, formatFolderTitle, + projectMembers, }) => { const renderLink = (link) => { if (link.onClick) { @@ -59,6 +61,7 @@ const LinksGridView = ({ renderLink={ renderLink } goBack={goBack} formatModifyDate={formatModifyDate} + projectMembers={projectMembers} isLinkSubFolder />)} {(!subFolderContent) && ( @@ -69,6 +72,7 @@ const LinksGridView = ({
  • Type
    Name
    +
    Created By
    Modified
  • @@ -87,12 +91,14 @@ const LinksGridView = ({ const onEditCancel = () => onEditIntent(-1) const handleEditClick = () => onEditIntent(idx) const changeSubFolder = () => onChangeSubFolder(link) + const owner = _.find(projectMembers, m => m.userId === _.parseInt(link.createdBy)) if (Array.isArray(link.children) && link.children.length > 0) { return (
  • {formatFolderTitle(link.title)}

    +
    {formatModifyDate(link)}
  • ) @@ -119,6 +125,15 @@ const LinksGridView = ({
  • {renderLink(link)}

    +
    + {!owner && (
    Unknown
    )} + {owner && ( +
    +
    + +
    +
    )} +
    {formatModifyDate(link)}
    {(canEdit || canDelete) && ( diff --git a/src/components/AssetsLibrary/SubFolder.jsx b/src/components/AssetsLibrary/SubFolder.jsx index e8680cbe4..9f96e545a 100644 --- a/src/components/AssetsLibrary/SubFolder.jsx +++ b/src/components/AssetsLibrary/SubFolder.jsx @@ -1,9 +1,11 @@ import React from 'react' import PropTypes from 'prop-types' +import _ from 'lodash' import cn from 'classnames' import DeleteFileLinkModal from '../LinksMenu/DeleteFileLinkModal' import ItemOperations from './ItemOperations' +import UserTooltip from '../User/UserTooltip' import FolderIcon from '../../assets/icons/v.2.5/icon-folder-small.svg' import './GridView.scss' @@ -54,7 +56,7 @@ class SubFolder extends React.Component { } render() { - const { link, renderLink, goBack, formatModifyDate, isLinkSubFolder } = this.props + const { link, renderLink, goBack, formatModifyDate, isLinkSubFolder, projectMembers } = this.props const { linkToDelete } = this.state return (
    = 0)}, '')}> @@ -64,17 +66,20 @@ class SubFolder extends React.Component {
  • Type
    Name
    +
    Created By
    Modified
  • ..
    +
  • { link.children.map((childLink, i) => { + const owner = _.find(projectMembers, m => m.userId === _.parseInt(childLink.createdBy)) if (linkToDelete === i) { return (
  • @@ -100,6 +105,16 @@ class SubFolder extends React.Component { return (
  • {renderLink(childLink)}

    +
    + {!owner && childLink.createdBy !== 'CoderBot' && (
    Unknown
    )} + {!owner && childLink.createdBy === 'CoderBot' && (
    CoderBot
    )} + {owner && ( +
    +
    + +
    +
    )} +
    {formatModifyDate(childLink)}
    {childLink.deletable && this.hasAccess(childLink.createdBy) && ( diff --git a/src/projects/detail/containers/AssetsInfoContainer.jsx b/src/projects/detail/containers/AssetsInfoContainer.jsx index b0a19d47c..152c9d1e4 100644 --- a/src/projects/detail/containers/AssetsInfoContainer.jsx +++ b/src/projects/detail/containers/AssetsInfoContainer.jsx @@ -223,7 +223,7 @@ class AssetsInfoContainer extends React.Component { this.props.uploadProjectAttachments(project.id, attachment) } - extractHtmlLink(str) { + extractHtmlLink(str, userId) { const links = [] const regex = /]+href="(.*?)"[^>]*>([\s\S]*?)<\/a>/gm const urlRegex = /^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$/gm // eslint-disable-line no-useless-escape @@ -238,7 +238,8 @@ class AssetsInfoContainer extends React.Component { if (urlRegex.test(address)) { links.push({ title, - address + address, + createdBy: userId }) } @@ -249,7 +250,7 @@ class AssetsInfoContainer extends React.Component { return links } - extractMarkdownLink(str) { + extractMarkdownLink(str, userId) { const links = [] const regex = /(?:__|[*#])|\[(.*?)\]\((.*?)\)/gm const urlRegex = /^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$/gm // eslint-disable-line no-useless-escape @@ -264,7 +265,8 @@ class AssetsInfoContainer extends React.Component { if (urlRegex.test(address)) { links.push({ title, - address + address, + createdBy: userId }) } @@ -275,7 +277,7 @@ class AssetsInfoContainer extends React.Component { return links } - extractRawLink(str) { + extractRawLink(str, userId) { let links = [] const regex = /(\s|^)(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,}[\s])(\s|$)/igm // eslint-disable-line no-useless-escape const rawLinks = str.match(regex) @@ -289,7 +291,8 @@ class AssetsInfoContainer extends React.Component { return { title: name, - address: url + address: url, + createdBy: userId } }) } @@ -303,9 +306,9 @@ class AssetsInfoContainer extends React.Component { let childrenLinks = [] feed.posts.forEach(post => { childrenLinks = childrenLinks.concat([ - ...this.extractHtmlLink(post.rawContent), - ...this.extractMarkdownLink(post.rawContent), - ...this.extractRawLink(post.rawContent) + ...this.extractHtmlLink(post.rawContent, post.userId), + ...this.extractMarkdownLink(post.rawContent, post.userId), + ...this.extractRawLink(post.rawContent, post.userId) ]) }) @@ -460,8 +463,22 @@ class AssetsInfoContainer extends React.Component { const privateTopicLinks = topicLinks.filter(link => link.tag === PROJECT_FEED_TYPE_MESSAGES) const phaseLinks = this.extractLinksFromPosts(phaseFeeds) + const bookmarks = [] + _.forEach(project.bookmarks, (b, index) => { + const bookmark = { + id: index, + title: b.title, + address: b.address, + createdAt: project.createdAt, + createdBy: project.createdBy, + updatedAt: project.updatedAt, + updatedBy: project.updatedBy + } + bookmarks.push(bookmark) + }) + let links = [] - links = links.concat(project.bookmarks) + links = links.concat(bookmarks) links = links.concat(publicTopicLinks) if (canAccessPrivatePosts) { links = links.concat(privateTopicLinks) @@ -607,6 +624,7 @@ class AssetsInfoContainer extends React.Component { {(!hideLinks && activeAssetsType === 'Links') && Date: Sat, 21 Sep 2019 09:49:20 +0800 Subject: [PATCH 2/6] bug #3273 Show Created By for files and links list in Assets Library 2 --- .../AssetsLibrary/LinksGridView.jsx | 3 +- .../detail/containers/AssetsInfoContainer.jsx | 30 ++++++++----------- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/src/components/AssetsLibrary/LinksGridView.jsx b/src/components/AssetsLibrary/LinksGridView.jsx index 33f23afa3..c87f9ea57 100644 --- a/src/components/AssetsLibrary/LinksGridView.jsx +++ b/src/components/AssetsLibrary/LinksGridView.jsx @@ -126,7 +126,8 @@ const LinksGridView = ({

    {renderLink(link)}

    - {!owner && (
    Unknown
    )} + {!owner && !link.createdBy && (
    )} + {!owner && link.createdBy && (
    Unknown
    )} {owner && (
    diff --git a/src/projects/detail/containers/AssetsInfoContainer.jsx b/src/projects/detail/containers/AssetsInfoContainer.jsx index 152c9d1e4..18b4a0eec 100644 --- a/src/projects/detail/containers/AssetsInfoContainer.jsx +++ b/src/projects/detail/containers/AssetsInfoContainer.jsx @@ -167,7 +167,11 @@ class AssetsInfoContainer extends React.Component { } onAddNewLink(link) { - const { updateProject, project } = this.props + const { updateProject, project, loggedInUser } = this.props + link.createdAt = moment().format('YYYY-MM-DDTHH:mm:ss.SSS[Z]') + link.createdBy = loggedInUser.userId + link.updatedAt = moment().format('YYYY-MM-DDTHH:mm:ss.SSS[Z]') + link.updatedBy = loggedInUser.userId updateProject(project.id, { bookmarks: update(project.bookmarks || [], { $push: [link] }) }) @@ -181,10 +185,14 @@ class AssetsInfoContainer extends React.Component { } onEditLink(idx, title, address) { - const { updateProject, project } = this.props + const { updateProject, project, loggedInUser } = this.props + const updatedAt = moment().format('YYYY-MM-DDTHH:mm:ss.SSS[Z]') + const updatedBy = loggedInUser.userId const updatedLink = { title, - address + address, + updatedAt, + updatedBy } updateProject(project.id, { bookmarks: update(project.bookmarks, { $splice: [[idx, 1, updatedLink]] }) @@ -463,22 +471,8 @@ class AssetsInfoContainer extends React.Component { const privateTopicLinks = topicLinks.filter(link => link.tag === PROJECT_FEED_TYPE_MESSAGES) const phaseLinks = this.extractLinksFromPosts(phaseFeeds) - const bookmarks = [] - _.forEach(project.bookmarks, (b, index) => { - const bookmark = { - id: index, - title: b.title, - address: b.address, - createdAt: project.createdAt, - createdBy: project.createdBy, - updatedAt: project.updatedAt, - updatedBy: project.updatedBy - } - bookmarks.push(bookmark) - }) - let links = [] - links = links.concat(bookmarks) + links = links.concat(project.bookmarks) links = links.concat(publicTopicLinks) if (canAccessPrivatePosts) { links = links.concat(privateTopicLinks) From d16dd9b35f30c2bbd4954d161be2d9fd1290c9af Mon Sep 17 00:00:00 2001 From: jankyzhang Date: Sun, 22 Sep 2019 13:29:57 +0800 Subject: [PATCH 3/6] bug #3273 Show Created By for files and links list in Assets Library 3 --- .../AssetsLibrary/FilesGridView.jsx | 5 ++-- .../AssetsLibrary/LinksGridView.jsx | 6 ++-- src/components/AssetsLibrary/SubFolder.jsx | 4 +-- src/config/constants.js | 5 ++++ src/projects/actions/project.js | 21 ++++++++++++++ .../detail/containers/AssetsInfoContainer.jsx | 29 ++++++++++++++++--- src/projects/reducers/project.js | 21 ++++++++++++++ 7 files changed, 80 insertions(+), 11 deletions(-) diff --git a/src/components/AssetsLibrary/FilesGridView.jsx b/src/components/AssetsLibrary/FilesGridView.jsx index 0b9a6bcd5..a35ac1e46 100644 --- a/src/components/AssetsLibrary/FilesGridView.jsx +++ b/src/components/AssetsLibrary/FilesGridView.jsx @@ -29,6 +29,7 @@ const FilesGridView = ({ title, selectedUsers, onAddAttachment, + assetsMembers, isSharingAttachment, discardAttachments, onChangePermissions, @@ -79,7 +80,7 @@ const FilesGridView = ({ link={ subFolderContent } renderLink={ renderLink } goBack={goBack} - projectMembers={projectMembers} + assetsMembers={assetsMembers} onDeletePostAttachment={onDeletePostAttachment} loggedInUser={loggedInUser} formatModifyDate={formatModifyDate} @@ -122,7 +123,7 @@ const FilesGridView = ({ const canEdit = `${link.createdBy}` === `${loggedInUser.userId}` const changeSubFolder = () => onChangeSubFolder(link) - const owner = _.find(projectMembers, m => m.userId === _.parseInt(link.createdBy)) + const owner = _.find(assetsMembers, m => m.userId === _.parseInt(link.createdBy)) if (Array.isArray(link.children) && link.children.length > 0) { return ( diff --git a/src/components/AssetsLibrary/LinksGridView.jsx b/src/components/AssetsLibrary/LinksGridView.jsx index c87f9ea57..f911e3fd7 100644 --- a/src/components/AssetsLibrary/LinksGridView.jsx +++ b/src/components/AssetsLibrary/LinksGridView.jsx @@ -29,7 +29,7 @@ const LinksGridView = ({ title, formatModifyDate, formatFolderTitle, - projectMembers, + assetsMembers, }) => { const renderLink = (link) => { if (link.onClick) { @@ -61,7 +61,7 @@ const LinksGridView = ({ renderLink={ renderLink } goBack={goBack} formatModifyDate={formatModifyDate} - projectMembers={projectMembers} + assetsMembers={assetsMembers} isLinkSubFolder />)} {(!subFolderContent) && ( @@ -91,7 +91,7 @@ const LinksGridView = ({ const onEditCancel = () => onEditIntent(-1) const handleEditClick = () => onEditIntent(idx) const changeSubFolder = () => onChangeSubFolder(link) - const owner = _.find(projectMembers, m => m.userId === _.parseInt(link.createdBy)) + const owner = _.find(assetsMembers, m => m.userId === _.parseInt(link.createdBy)) if (Array.isArray(link.children) && link.children.length > 0) { return ( diff --git a/src/components/AssetsLibrary/SubFolder.jsx b/src/components/AssetsLibrary/SubFolder.jsx index 9f96e545a..a23cac3ba 100644 --- a/src/components/AssetsLibrary/SubFolder.jsx +++ b/src/components/AssetsLibrary/SubFolder.jsx @@ -56,7 +56,7 @@ class SubFolder extends React.Component { } render() { - const { link, renderLink, goBack, formatModifyDate, isLinkSubFolder, projectMembers } = this.props + const { link, renderLink, goBack, formatModifyDate, isLinkSubFolder, assetsMembers } = this.props const { linkToDelete } = this.state return (
    = 0)}, '')}> @@ -79,7 +79,7 @@ class SubFolder extends React.Component {
  • { link.children.map((childLink, i) => { - const owner = _.find(projectMembers, m => m.userId === _.parseInt(childLink.createdBy)) + const owner = _.find(assetsMembers, m => m.userId === _.parseInt(childLink.createdBy)) if (linkToDelete === i) { return (
  • diff --git a/src/config/constants.js b/src/config/constants.js index 0025df4a4..d1d91b8d0 100644 --- a/src/config/constants.js +++ b/src/config/constants.js @@ -328,6 +328,11 @@ export const LOAD_MEMBERS_PENDING = 'LOAD_MEMBERS_PENDING' export const LOAD_MEMBERS_SUCCESS = 'LOAD_MEMBERS_SUCCESS' export const LOAD_MEMBERS_FAILURE = 'LOAD_MEMBERS_FAILURE' +export const LOAD_ASSETS_MEMBERS = 'LOAD_ASSETS_MEMBERS' +export const LOAD_ASSETS_MEMBERS_PENDING = 'LOAD_ASSETS_MEMBERS_PENDING' +export const LOAD_ASSETS_MEMBERS_SUCCESS = 'LOAD_ASSETS_MEMBERS_SUCCESS' +export const LOAD_ASSETS_MEMBERS_FAILURE = 'LOAD_ASSETS_MEMBERS_FAILURE' + export const LOAD_MEMBER_SUGGESTIONS = 'LOAD_MEMBER_SUGGESTIONS' export const LOAD_MEMBER_SUGGESTIONS_PENDING = 'LOAD_MEMBER_SUGGESTIONS_PENDING' export const LOAD_MEMBER_SUGGESTIONS_SUCCESS = 'LOAD_MEMBER_SUGGESTIONS_SUCCESS' diff --git a/src/projects/actions/project.js b/src/projects/actions/project.js index fae5dbcb7..e0a0593cf 100644 --- a/src/projects/actions/project.js +++ b/src/projects/actions/project.js @@ -21,6 +21,7 @@ import { import { createTimeline, } from '../../api/timelines' +import { getMembersById } from '../../api/projectMembers' // import { loadProductTimelineWithMilestones } from './productsTimelines' import { LOAD_PROJECT, @@ -44,6 +45,7 @@ import { PHASE_STATUS_ACTIVE, PHASE_DIRTY, PHASE_DIRTY_UNDO, + LOAD_ASSETS_MEMBERS, PROJECT_STATUS_IN_REVIEW, PHASE_STATUS_REVIEWED, PROJECT_STATUS_REVIEWED, @@ -331,6 +333,25 @@ export function updateProject(projectId, updatedProps, updateExisting = false) { } } +export function loadAssetsMembers(userIds) { + return (dispatch, getState) => { + // check if we need to request data from server + const assetsMembers = getState().projectState.assetsMembers + // this returns ids from userIds that are not in store (members) + const missingUsers = _.difference(userIds, _.keys(assetsMembers)) + // dispatch request to load members if we are missing data + if (missingUsers.length) { + return dispatch({ + type: LOAD_ASSETS_MEMBERS, + payload: getMembersById(userIds) + }) + } else { + // returns empty resolved promise to avoid error when we call then on this action + return Promise.resolve() + } + } +} + export function createScopeChangeRequest(projectId, request) { const flatNewScope = flatten(request.newScope, { safe: true }) const emptyKeys = _.keys(flatNewScope).filter(key => { diff --git a/src/projects/detail/containers/AssetsInfoContainer.jsx b/src/projects/detail/containers/AssetsInfoContainer.jsx index 18b4a0eec..9e03434c7 100644 --- a/src/projects/detail/containers/AssetsInfoContainer.jsx +++ b/src/projects/detail/containers/AssetsInfoContainer.jsx @@ -9,7 +9,7 @@ import moment from 'moment' import LinksGridView from '../../../components/AssetsLibrary/LinksGridView' import FilesGridView from '../../../components/AssetsLibrary/FilesGridView' import AssetsStatistics from '../../../components/AssetsLibrary/AssetsStatistics' -import { updateProject, deleteProject } from '../../actions/project' +import { updateProject, deleteProject, loadAssetsMembers } from '../../actions/project' import { loadDashboardFeeds, loadProjectMessages } from '../../actions/projectTopics' import { loadTopic } from '../../../actions/topics' import { loadProjectPlan } from '../../actions/projectPlan' @@ -397,7 +397,7 @@ class AssetsInfoContainer extends React.Component { const { project, currentMemberRole, isSuperUser, phases, feeds, isManageUser, phasesTopics, projectTemplates, hideLinks, attachmentsAwaitingPermission, addProjectAttachment, discardAttachments, attachmentPermissions, - changeAttachmentPermission, projectMembers, loggedInUser, isSharingAttachment, canAccessPrivatePosts } = this.props + changeAttachmentPermission, projectMembers, loggedInUser, isSharingAttachment, canAccessPrivatePosts, loadAssetsMembers, assetsMembers } = this.props const { ifModalOpen } = this.state const canManageLinks = !!currentMemberRole || isSuperUser @@ -486,6 +486,25 @@ class AssetsInfoContainer extends React.Component { ...this.extractAttachmentLinksFromPosts(phaseFeeds) ] + let tmpUserIds = [] + let userIds = [] + _.forEach(links, link => { + tmpUserIds = _.union(tmpUserIds, _.map(link.children, 'createdBy')) + tmpUserIds = _.union(tmpUserIds, [link.createdBy]) + tmpUserIds = _.union(tmpUserIds, [link.updatedBy]) + }) + + _.forEach(attachments, attachment => { + tmpUserIds = _.union(tmpUserIds, _.map(attachment.children, 'createdBy')) + tmpUserIds = _.union(tmpUserIds, [attachment.createdBy]) + }) + + _.forEach(tmpUserIds, userId => { + userIds = _.union(userIds, [_.parseInt(userId)]) + }) + _.remove(userIds, i => !i) + loadAssetsMembers(userIds) + const assetsData = [] enableFileUpload && assetsData.push({name: 'Files', total: _.toString(attachments.length)}) !hideLinks && assetsData.push({name: 'Links', total: _.toString(links.length)}) @@ -608,6 +627,7 @@ class AssetsInfoContainer extends React.Component { onChangePermissions={changeAttachmentPermission} selectedUsers={attachmentPermissions} projectMembers={projectMembers} + assetsMembers={assetsMembers} pendingAttachments={attachmentsAwaitingPermission} loggedInUser={loggedInUser} attachmentsStorePath={attachmentsStorePath} @@ -618,7 +638,7 @@ class AssetsInfoContainer extends React.Component { {(!hideLinks && activeAssetsType === 'Links') && { attachmentPermissions: projectState.attachmentPermissions, isSharingAttachment: projectState.processingAttachments, projectMembers: _.keyBy(projectMembers, 'userId'), + assetsMembers: _.keyBy(projectState.assetsMembers, 'userId'), loggedInUser: loadUser.user, canAccessPrivatePosts }) } -const mapDispatchToProps = { updateProject, deleteProject, addProjectAttachment, updateProjectAttachment, +const mapDispatchToProps = { updateProject, deleteProject, loadAssetsMembers, addProjectAttachment, updateProjectAttachment, loadProjectMessages, discardAttachments, uploadProjectAttachments, loadDashboardFeeds, loadTopic, changeAttachmentPermission, removeProjectAttachment, loadProjectPlan, saveFeedComment } diff --git a/src/projects/reducers/project.js b/src/projects/reducers/project.js index 6abe03f07..c22d40777 100644 --- a/src/projects/reducers/project.js +++ b/src/projects/reducers/project.js @@ -23,6 +23,7 @@ import { ACCEPT_OR_REFUSE_INVITE_SUCCESS, ACCEPT_OR_REFUSE_INVITE_FAILURE, ACCEPT_OR_REFUSE_INVITE_PENDING, RELOAD_PROJECT_MEMBERS_SUCCESS, UPLOAD_PROJECT_ATTACHMENT_FILES, DISCARD_PROJECT_ATTACHMENT, CHANGE_ATTACHMENT_PERMISSION, CREATE_SCOPE_CHANGE_REQUEST_SUCCESS, APPROVE_SCOPE_CHANGE_SUCCESS, REJECT_SCOPE_CHANGE_SUCCESS, CANCEL_SCOPE_CHANGE_SUCCESS, ACTIVATE_SCOPE_CHANGE_SUCCESS, + LOAD_ASSETS_MEMBERS_SUCCESS, LOAD_ASSETS_MEMBERS_PENDING, LOAD_ASSETS_MEMBERS_FAILURE, CONNECT_USER, CONNECT_USER_HANDLE } from '../../config/constants' import _ from 'lodash' import update from 'react-addons-update' @@ -40,6 +41,7 @@ const initialState = { project: { invites: [] // invites are pushed directly into it hence need to declare first }, + assetsMembers: {}, projectNonDirty: {}, updateExisting: false, phases: null, @@ -439,6 +441,25 @@ export const projectState = function (state=initialState, action) { }) } + case LOAD_ASSETS_MEMBERS_SUCCESS: { + const _members = _.map(_.filter(action.payload, m => m.userId), m => { + if (m.handle) { + return m + } + return { userId: m.userId, ...CONNECT_USER, handle: CONNECT_USER_HANDLE } + }) + const userMap = _.keyBy(_members, 'userId') + // merge the 2 data sets + return Object.assign({}, state, { + processing: false, + assetsMembers: update(state.assetsMembers, {$merge: userMap}), + }) + } + + case LOAD_ASSETS_MEMBERS_PENDING: + case LOAD_ASSETS_MEMBERS_FAILURE: + return state + case DELETE_PROJECT_PHASE_SUCCESS: { const { phaseId } = action.payload From 074f8e26c1958b3481ca5f4aacbd30ad3fd48bd6 Mon Sep 17 00:00:00 2001 From: jankyzhang Date: Sun, 29 Sep 2019 14:45:11 +0800 Subject: [PATCH 4/6] bug #3273 Show Created By for files and links list in Assets Library 4 --- src/components/AssetsLibrary/GridView.scss | 7 +++++++ src/config/constants.js | 5 ----- src/projects/actions/project.js | 21 ------------------- .../detail/containers/AssetsInfoContainer.jsx | 11 +++++----- src/projects/reducers/project.js | 20 ------------------ 5 files changed, 13 insertions(+), 51 deletions(-) diff --git a/src/components/AssetsLibrary/GridView.scss b/src/components/AssetsLibrary/GridView.scss index bad510657..638539628 100644 --- a/src/components/AssetsLibrary/GridView.scss +++ b/src/components/AssetsLibrary/GridView.scss @@ -134,4 +134,11 @@ .assets-gridview-container-active { position: relative; +} + +:global { + .user-block .tooltip-container { + text-align: left; + line-height: 20px; + } } \ No newline at end of file diff --git a/src/config/constants.js b/src/config/constants.js index d1d91b8d0..0025df4a4 100644 --- a/src/config/constants.js +++ b/src/config/constants.js @@ -328,11 +328,6 @@ export const LOAD_MEMBERS_PENDING = 'LOAD_MEMBERS_PENDING' export const LOAD_MEMBERS_SUCCESS = 'LOAD_MEMBERS_SUCCESS' export const LOAD_MEMBERS_FAILURE = 'LOAD_MEMBERS_FAILURE' -export const LOAD_ASSETS_MEMBERS = 'LOAD_ASSETS_MEMBERS' -export const LOAD_ASSETS_MEMBERS_PENDING = 'LOAD_ASSETS_MEMBERS_PENDING' -export const LOAD_ASSETS_MEMBERS_SUCCESS = 'LOAD_ASSETS_MEMBERS_SUCCESS' -export const LOAD_ASSETS_MEMBERS_FAILURE = 'LOAD_ASSETS_MEMBERS_FAILURE' - export const LOAD_MEMBER_SUGGESTIONS = 'LOAD_MEMBER_SUGGESTIONS' export const LOAD_MEMBER_SUGGESTIONS_PENDING = 'LOAD_MEMBER_SUGGESTIONS_PENDING' export const LOAD_MEMBER_SUGGESTIONS_SUCCESS = 'LOAD_MEMBER_SUGGESTIONS_SUCCESS' diff --git a/src/projects/actions/project.js b/src/projects/actions/project.js index e0a0593cf..fae5dbcb7 100644 --- a/src/projects/actions/project.js +++ b/src/projects/actions/project.js @@ -21,7 +21,6 @@ import { import { createTimeline, } from '../../api/timelines' -import { getMembersById } from '../../api/projectMembers' // import { loadProductTimelineWithMilestones } from './productsTimelines' import { LOAD_PROJECT, @@ -45,7 +44,6 @@ import { PHASE_STATUS_ACTIVE, PHASE_DIRTY, PHASE_DIRTY_UNDO, - LOAD_ASSETS_MEMBERS, PROJECT_STATUS_IN_REVIEW, PHASE_STATUS_REVIEWED, PROJECT_STATUS_REVIEWED, @@ -333,25 +331,6 @@ export function updateProject(projectId, updatedProps, updateExisting = false) { } } -export function loadAssetsMembers(userIds) { - return (dispatch, getState) => { - // check if we need to request data from server - const assetsMembers = getState().projectState.assetsMembers - // this returns ids from userIds that are not in store (members) - const missingUsers = _.difference(userIds, _.keys(assetsMembers)) - // dispatch request to load members if we are missing data - if (missingUsers.length) { - return dispatch({ - type: LOAD_ASSETS_MEMBERS, - payload: getMembersById(userIds) - }) - } else { - // returns empty resolved promise to avoid error when we call then on this action - return Promise.resolve() - } - } -} - export function createScopeChangeRequest(projectId, request) { const flatNewScope = flatten(request.newScope, { safe: true }) const emptyKeys = _.keys(flatNewScope).filter(key => { diff --git a/src/projects/detail/containers/AssetsInfoContainer.jsx b/src/projects/detail/containers/AssetsInfoContainer.jsx index 9e03434c7..ad74716eb 100644 --- a/src/projects/detail/containers/AssetsInfoContainer.jsx +++ b/src/projects/detail/containers/AssetsInfoContainer.jsx @@ -9,7 +9,8 @@ import moment from 'moment' import LinksGridView from '../../../components/AssetsLibrary/LinksGridView' import FilesGridView from '../../../components/AssetsLibrary/FilesGridView' import AssetsStatistics from '../../../components/AssetsLibrary/AssetsStatistics' -import { updateProject, deleteProject, loadAssetsMembers } from '../../actions/project' +import { updateProject, deleteProject } from '../../actions/project' +import { loadMembers } from '../../../actions/members' import { loadDashboardFeeds, loadProjectMessages } from '../../actions/projectTopics' import { loadTopic } from '../../../actions/topics' import { loadProjectPlan } from '../../actions/projectPlan' @@ -397,7 +398,7 @@ class AssetsInfoContainer extends React.Component { const { project, currentMemberRole, isSuperUser, phases, feeds, isManageUser, phasesTopics, projectTemplates, hideLinks, attachmentsAwaitingPermission, addProjectAttachment, discardAttachments, attachmentPermissions, - changeAttachmentPermission, projectMembers, loggedInUser, isSharingAttachment, canAccessPrivatePosts, loadAssetsMembers, assetsMembers } = this.props + changeAttachmentPermission, projectMembers, loggedInUser, isSharingAttachment, canAccessPrivatePosts, loadMembers, assetsMembers } = this.props const { ifModalOpen } = this.state const canManageLinks = !!currentMemberRole || isSuperUser @@ -503,7 +504,7 @@ class AssetsInfoContainer extends React.Component { userIds = _.union(userIds, [_.parseInt(userId)]) }) _.remove(userIds, i => !i) - loadAssetsMembers(userIds) + loadMembers(userIds) const assetsData = [] enableFileUpload && assetsData.push({name: 'Files', total: _.toString(attachments.length)}) @@ -673,13 +674,13 @@ const mapStateToProps = ({ templates, projectState, members, loadUser }) => { attachmentPermissions: projectState.attachmentPermissions, isSharingAttachment: projectState.processingAttachments, projectMembers: _.keyBy(projectMembers, 'userId'), - assetsMembers: _.keyBy(projectState.assetsMembers, 'userId'), + assetsMembers: _.keyBy(members.members, 'userId'), loggedInUser: loadUser.user, canAccessPrivatePosts }) } -const mapDispatchToProps = { updateProject, deleteProject, loadAssetsMembers, addProjectAttachment, updateProjectAttachment, +const mapDispatchToProps = { updateProject, deleteProject, loadMembers, addProjectAttachment, updateProjectAttachment, loadProjectMessages, discardAttachments, uploadProjectAttachments, loadDashboardFeeds, loadTopic, changeAttachmentPermission, removeProjectAttachment, loadProjectPlan, saveFeedComment } diff --git a/src/projects/reducers/project.js b/src/projects/reducers/project.js index c22d40777..8b7e28993 100644 --- a/src/projects/reducers/project.js +++ b/src/projects/reducers/project.js @@ -23,7 +23,6 @@ import { ACCEPT_OR_REFUSE_INVITE_SUCCESS, ACCEPT_OR_REFUSE_INVITE_FAILURE, ACCEPT_OR_REFUSE_INVITE_PENDING, RELOAD_PROJECT_MEMBERS_SUCCESS, UPLOAD_PROJECT_ATTACHMENT_FILES, DISCARD_PROJECT_ATTACHMENT, CHANGE_ATTACHMENT_PERMISSION, CREATE_SCOPE_CHANGE_REQUEST_SUCCESS, APPROVE_SCOPE_CHANGE_SUCCESS, REJECT_SCOPE_CHANGE_SUCCESS, CANCEL_SCOPE_CHANGE_SUCCESS, ACTIVATE_SCOPE_CHANGE_SUCCESS, - LOAD_ASSETS_MEMBERS_SUCCESS, LOAD_ASSETS_MEMBERS_PENDING, LOAD_ASSETS_MEMBERS_FAILURE, CONNECT_USER, CONNECT_USER_HANDLE } from '../../config/constants' import _ from 'lodash' import update from 'react-addons-update' @@ -441,25 +440,6 @@ export const projectState = function (state=initialState, action) { }) } - case LOAD_ASSETS_MEMBERS_SUCCESS: { - const _members = _.map(_.filter(action.payload, m => m.userId), m => { - if (m.handle) { - return m - } - return { userId: m.userId, ...CONNECT_USER, handle: CONNECT_USER_HANDLE } - }) - const userMap = _.keyBy(_members, 'userId') - // merge the 2 data sets - return Object.assign({}, state, { - processing: false, - assetsMembers: update(state.assetsMembers, {$merge: userMap}), - }) - } - - case LOAD_ASSETS_MEMBERS_PENDING: - case LOAD_ASSETS_MEMBERS_FAILURE: - return state - case DELETE_PROJECT_PHASE_SUCCESS: { const { phaseId } = action.payload From 568c5f4ca79aa799f9591680549f8aa4cfcd18fe Mon Sep 17 00:00:00 2001 From: jankyzhang Date: Mon, 30 Sep 2019 01:36:28 +0800 Subject: [PATCH 5/6] bug #3273 Show Created By for files and links list in Assets Library 5 --- src/components/AssetsLibrary/FilesGridView.jsx | 2 +- src/components/AssetsLibrary/LinksGridView.jsx | 2 +- src/projects/detail/containers/AssetsInfoContainer.jsx | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/AssetsLibrary/FilesGridView.jsx b/src/components/AssetsLibrary/FilesGridView.jsx index a35ac1e46..a5ea04d09 100644 --- a/src/components/AssetsLibrary/FilesGridView.jsx +++ b/src/components/AssetsLibrary/FilesGridView.jsx @@ -172,7 +172,7 @@ const FilesGridView = ({ {owner && (
    - +
    )}
  • diff --git a/src/components/AssetsLibrary/LinksGridView.jsx b/src/components/AssetsLibrary/LinksGridView.jsx index f911e3fd7..8f211347a 100644 --- a/src/components/AssetsLibrary/LinksGridView.jsx +++ b/src/components/AssetsLibrary/LinksGridView.jsx @@ -131,7 +131,7 @@ const LinksGridView = ({ {owner && (
    - +
    )} diff --git a/src/projects/detail/containers/AssetsInfoContainer.jsx b/src/projects/detail/containers/AssetsInfoContainer.jsx index ad74716eb..513b32b6d 100644 --- a/src/projects/detail/containers/AssetsInfoContainer.jsx +++ b/src/projects/detail/containers/AssetsInfoContainer.jsx @@ -504,7 +504,10 @@ class AssetsInfoContainer extends React.Component { userIds = _.union(userIds, [_.parseInt(userId)]) }) _.remove(userIds, i => !i) - loadMembers(userIds) + const missingUsers = _.filter(userIds, userId => !_.find(assetsMembers, am => am.userId === userId)) + if (missingUsers.length) { + loadMembers(missingUsers) + } const assetsData = [] enableFileUpload && assetsData.push({name: 'Files', total: _.toString(attachments.length)}) From 865349cf3fab7e8a02f11ba16e04934c58a072f6 Mon Sep 17 00:00:00 2001 From: jankyzhang Date: Mon, 30 Sep 2019 13:50:46 +0800 Subject: [PATCH 6/6] bug #3273 Show Created By for files and links list in Assets Library 6 --- .../detail/containers/AssetsInfoContainer.jsx | 73 +++++++++++-------- 1 file changed, 44 insertions(+), 29 deletions(-) diff --git a/src/projects/detail/containers/AssetsInfoContainer.jsx b/src/projects/detail/containers/AssetsInfoContainer.jsx index 513b32b6d..6ee6fc61a 100644 --- a/src/projects/detail/containers/AssetsInfoContainer.jsx +++ b/src/projects/detail/containers/AssetsInfoContainer.jsx @@ -69,6 +69,7 @@ class AssetsInfoContainer extends React.Component { !_.isEqual(nextProps.attachmentsAwaitingPermission, this.props.attachmentsAwaitingPermission) || !_.isEqual(nextProps.attachmentPermissions, this.props.attachmentPermissions) || !_.isEqual(nextProps.isSharingAttachment, this.props.isSharingAttachment) || + !_.isEqual(nextProps.assetsMembers, this.props.assetsMembers) || !_.isEqual(nextState.activeAssetsType, this.state.activeAssetsType) || !_.isEqual(nextState.ifModalOpen, this.state.ifModalOpen) } @@ -394,22 +395,9 @@ class AssetsInfoContainer extends React.Component { } } - render() { - const { project, currentMemberRole, isSuperUser, phases, feeds, - isManageUser, phasesTopics, projectTemplates, hideLinks, - attachmentsAwaitingPermission, addProjectAttachment, discardAttachments, attachmentPermissions, - changeAttachmentPermission, projectMembers, loggedInUser, isSharingAttachment, canAccessPrivatePosts, loadMembers, assetsMembers } = this.props - const { ifModalOpen } = this.state - - const canManageLinks = !!currentMemberRole || isSuperUser - - let devices = [] - const primaryTarget = _.get(project, 'details.appDefinition.primaryTarget') - if (primaryTarget && !primaryTarget.seeAttached) { - devices.push(primaryTarget.value) - } else { - devices = _.get(project, 'details.devices', []) - } + getLinksAndAttachments() { + const { project, isSuperUser, phases, feeds, + isManageUser, phasesTopics, canAccessPrivatePosts } = this.props let attachments = project.attachments // merges the product attachments to show in the links menu @@ -456,16 +444,6 @@ class AssetsInfoContainer extends React.Component { }) ) - const attachmentsStorePath = `${PROJECT_ATTACHMENTS_FOLDER}/${project.id}/` - let enableFileUpload = true - if(project.version !== 'v2') { - const templateId = _.get(project, 'templateId') - const projectTemplate = _.find(projectTemplates, template => template.id === templateId) - enableFileUpload = _.some(projectTemplate.scope.sections, section => { - return _.some(section.subSections, subSection => subSection.id === 'files') - }) - } - // extract links from posts const topicLinks = this.extractLinksFromPosts(feeds) const publicTopicLinks = topicLinks.filter(link => link.tag !== PROJECT_FEED_TYPE_MESSAGES) @@ -487,6 +465,16 @@ class AssetsInfoContainer extends React.Component { ...this.extractAttachmentLinksFromPosts(phaseFeeds) ] + return ({ + links, + attachments, + }) + } + + componentDidMount() { + const {loadMembers } = this.props + const {links, attachments} = this.getLinksAndAttachments() + let tmpUserIds = [] let userIds = [] _.forEach(links, link => { @@ -504,9 +492,36 @@ class AssetsInfoContainer extends React.Component { userIds = _.union(userIds, [_.parseInt(userId)]) }) _.remove(userIds, i => !i) - const missingUsers = _.filter(userIds, userId => !_.find(assetsMembers, am => am.userId === userId)) - if (missingUsers.length) { - loadMembers(missingUsers) + + loadMembers(userIds) + } + + render() { + const { project, currentMemberRole, isSuperUser, projectTemplates, hideLinks, + attachmentsAwaitingPermission, addProjectAttachment, discardAttachments, attachmentPermissions, + changeAttachmentPermission, projectMembers, loggedInUser, isSharingAttachment, assetsMembers } = this.props + const { ifModalOpen } = this.state + + const canManageLinks = !!currentMemberRole || isSuperUser + + let devices = [] + const primaryTarget = _.get(project, 'details.appDefinition.primaryTarget') + if (primaryTarget && !primaryTarget.seeAttached) { + devices.push(primaryTarget.value) + } else { + devices = _.get(project, 'details.devices', []) + } + + const {links, attachments} = this.getLinksAndAttachments() + + const attachmentsStorePath = `${PROJECT_ATTACHMENTS_FOLDER}/${project.id}/` + let enableFileUpload = true + if(project.version !== 'v2') { + const templateId = _.get(project, 'templateId') + const projectTemplate = _.find(projectTemplates, template => template.id === templateId) + enableFileUpload = _.some(projectTemplate.scope.sections, section => { + return _.some(section.subSections, subSection => subSection.id === 'files') + }) } const assetsData = []