Skip to content

Commit

Permalink
Merge pull request #4278 from NCI-Agency/AB-758-add-breadcrumb-trail-…
Browse files Browse the repository at this point in the history
…for-tasks

Add breadcrumb trail for tasks
  • Loading branch information
midmarch authored Mar 17, 2023
2 parents 8380fe7 + 79c6518 commit d0a9f63
Show file tree
Hide file tree
Showing 39 changed files with 461 additions and 162 deletions.
69 changes: 69 additions & 0 deletions client/src/components/BreadcrumbTrail.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import LinkTo from "components/LinkTo"
import PropTypes from "prop-types"
import React from "react"

const getBreadcrumbTrail = (leaf, ascendantObjects, parentField) => {
const parentMap =
ascendantObjects?.reduce((acc, val) => {
acc[val.uuid] = val
return acc
}, {}) || {}
parentMap[leaf.uuid] = leaf
let uuid = leaf.uuid
const trail = []
while (uuid) {
const node = parentMap[uuid]
if (!node) {
break
}
trail.unshift(node)
uuid = node[parentField]?.uuid
}
return trail
}

export const getBreadcrumbTrailAsText = (
leaf,
ascendantObjects,
parentField,
labelField
) => {
const trail = getBreadcrumbTrail(leaf, ascendantObjects, parentField)
return trail.map(node => node[labelField]).join(" » ")
}

export const BreadcrumbTrail = ({
modelType,
leaf,
ascendantObjects,
parentField,
isLink,
style
}) => {
const trail = getBreadcrumbTrail(leaf, ascendantObjects, parentField)
return (
<span>
{trail.map((node, i) => (
<React.Fragment key={node.uuid}>
{i > 0 && " » "}
<LinkTo
modelType={modelType}
model={node}
showIcon={false}
isLink={isLink}
style={style}
/>
</React.Fragment>
))}
</span>
)
}

BreadcrumbTrail.propTypes = {
modelType: PropTypes.string.isRequired,
leaf: PropTypes.object.isRequired,
ascendantObjects: PropTypes.array,
parentField: PropTypes.string.isRequired,
isLink: PropTypes.bool,
style: PropTypes.object
}
61 changes: 36 additions & 25 deletions client/src/components/FieldHelper.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { Icon } from "@blueprintjs/core"
import { IconNames } from "@blueprintjs/icons"
import classNames from "classnames"
import { BreadcrumbTrail } from "components/BreadcrumbTrail"
import { CompactRow } from "components/Compact"
import LinkTo from "components/LinkTo"
import RemoveButton from "components/RemoveButton"
import _cloneDeep from "lodash/cloneDeep"
import _get from "lodash/get"
import _isEmpty from "lodash/isEmpty"
import { Task } from "models"
import PropTypes from "prop-types"
import React, { useCallback, useMemo } from "react"
import {
Expand Down Expand Up @@ -608,32 +610,41 @@ export const FieldShortcuts = ({
onChange,
handleAddItem,
title
}) =>
shortcuts &&
shortcuts.length > 0 && (
<div id={`${fieldName}-shortcut-list`} className="shortcut-list">
<h5>{title}</h5>
<ListGroup>
{objectType.map(shortcuts, (shortcut, idx) => (
<ListGroup.Item key={shortcut.uuid}>
<Button
onClick={() => handleAddItem(shortcut, onChange, curValue)}
variant="secondary"
size="sm"
>
<Icon icon={IconNames.DOUBLE_CHEVRON_LEFT} />
</Button>
<LinkTo
modelType={objectType.resourceName}
model={shortcut}
isLink={false}
forShortcut
/>
</ListGroup.Item>
))}
</ListGroup>
</div>
}) => {
const modelType = objectType.resourceName
return (
shortcuts &&
shortcuts.length > 0 && (
<div id={`${fieldName}-shortcut-list`} className="shortcut-list">
<h5>{title}</h5>
<ListGroup>
{objectType.map(shortcuts, (shortcut, idx) => (
<ListGroup.Item key={shortcut.uuid}>
<Button
onClick={() => handleAddItem(shortcut, onChange, curValue)}
variant="secondary"
size="sm"
>
<Icon icon={IconNames.DOUBLE_CHEVRON_LEFT} />
</Button>
{modelType === Task.resourceName ? (
<BreadcrumbTrail
modelType={modelType}
leaf={shortcut}
ascendantObjects={shortcut.ascendantTasks}
parentField="parentTask"
isLink={false}
/>
) : (
<LinkTo modelType={modelType} model={shortcut} isLink={false} />
)}
</ListGroup.Item>
))}
</ListGroup>
</div>
)
)
}

FieldShortcuts.propTypes = {
shortcuts: PropTypes.arrayOf(PropTypes.shape({ uuid: PropTypes.string })),
Expand Down
10 changes: 7 additions & 3 deletions client/src/components/Kanban.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Icon } from "@blueprintjs/core"
import { IconNames } from "@blueprintjs/icons"
import { BreadcrumbTrail } from "components/BreadcrumbTrail"
import Pie from "components/graphs/Pie"
import LinkTo from "components/LinkTo"
import { EngagementTrends } from "components/Trends"
Expand Down Expand Up @@ -141,9 +142,12 @@ const CardView = ({ task }) => {
}}
>
<div>
<LinkTo modelType="Task" model={task}>
<strong>{task.shortName}</strong>
</LinkTo>
<BreadcrumbTrail
modelType="Task"
leaf={task}
ascendantObjects={task.ascendantTasks}
parentField="parentTask"
/>
<br />
<EngagementTrends
newValue={task.lastMonthReports.length}
Expand Down
24 changes: 7 additions & 17 deletions client/src/components/NoPaginationTaskTable.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { BreadcrumbTrail } from "components/BreadcrumbTrail"
import LinkTo from "components/LinkTo"
import RemoveButton from "components/RemoveButton"
import _get from "lodash/get"
Expand All @@ -10,7 +11,6 @@ import Settings from "settings"
const NoPaginationTaskTable = ({
id,
tasks,
showParent,
showOrganization,
showDelete,
showDescription,
Expand All @@ -26,9 +26,6 @@ const NoPaginationTaskTable = ({
<thead>
<tr>
<th>Name</th>
{showParent && (
<th>{Settings.fields.task.topLevel.shortLabel}</th>
)}
{showOrganization && <th>Tasked organizations</th>}
{showDescription && <th>Description</th>}
<th />
Expand All @@ -40,19 +37,13 @@ const NoPaginationTaskTable = ({
return (
<tr key={task.uuid}>
<td className="taskName">
<LinkTo modelType="Task" model={task}>
{task.shortName}
</LinkTo>
<BreadcrumbTrail
modelType="Task"
leaf={task}
ascendantObjects={task.ascendantTasks}
parentField="parentTask"
/>
</td>
{showParent && (
<td className="parentTaskName">
{task.parentTask && (
<LinkTo modelType="Task" model={task.parentTask}>
{task.parentTask.shortName}
</LinkTo>
)}
</td>
)}
{showOrganization && (
<td className="taskOrg">
{task.taskedOrganizations.map(org => (
Expand Down Expand Up @@ -92,7 +83,6 @@ const NoPaginationTaskTable = ({
NoPaginationTaskTable.propTypes = {
id: PropTypes.string,
tasks: PropTypes.array,
showParent: PropTypes.bool,
showDelete: PropTypes.bool,
onDelete: PropTypes.func,
showOrganization: PropTypes.bool,
Expand Down
18 changes: 15 additions & 3 deletions client/src/components/PendingAssessmentsByPosition.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { gql } from "@apollo/client"
import API from "api"
import { BreadcrumbTrail } from "components/BreadcrumbTrail"
import Fieldset from "components/Fieldset"
import LinkTo from "components/LinkTo"
import {
Expand Down Expand Up @@ -78,6 +79,14 @@ const GQL_GET_POSITION_LIST = gql`
longName
parentTask {
uuid
shortName
}
ascendantTasks(query: { pageNum: 0, pageSize: 0 }) {
uuid
shortName
parentTask {
uuid
}
}
${GRAPHQL_NOTIFICATIONS_NOTE_FIELDS}
}
Expand Down Expand Up @@ -285,9 +294,12 @@ const TaskList = ({ tasks }) => {
return (
<tr key={task.uuid}>
<td>
<LinkTo modelType="Task" model={task}>
{task.shortName} {task.longName}
</LinkTo>
<BreadcrumbTrail
modelType="Task"
leaf={task}
ascendantObjects={task.ascendantTasks}
parentField="parentTask"
/>
</td>
</tr>
)
Expand Down
30 changes: 26 additions & 4 deletions client/src/components/ReportSummary.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { gql } from "@apollo/client"
import API from "api"
import { BreadcrumbTrail } from "components/BreadcrumbTrail"
import LinkTo from "components/LinkTo"
import { PageDispatchersPropType, useBoilerplate } from "components/Page"
import { ReportCompactWorkflow } from "components/ReportWorkflow"
Expand All @@ -13,6 +14,7 @@ import pluralize from "pluralize"
import PropTypes from "prop-types"
import React, { useEffect, useRef, useState } from "react"
import { Badge, Col, Container, Row } from "react-bootstrap"
import TASKS_ICON from "resources/tasks.png"
import Settings from "settings"
import utils from "utils"

Expand Down Expand Up @@ -63,6 +65,17 @@ const GQL_GET_REPORT_LIST = gql`
tasks {
uuid
shortName
parentTask {
uuid
shortName
}
ascendantTasks(query: { pageNum: 0, pageSize: 0 }) {
uuid
shortName
parentTask {
uuid
}
}
}
workflow {
type
Expand Down Expand Up @@ -327,10 +340,19 @@ const ReportSummaryRow = ({ report }) => {
<strong>
{pluralize(Settings.fields.task.subLevel.shortLabel)}:
</strong>{" "}
{report.tasks.map(
(task, i) =>
task.shortName + (i < report.tasks.length - 1 ? ", " : "")
)}
{report.tasks.map((task, i) => (
<React.Fragment key={task.uuid}>
{i > 0 && (
<img src={TASKS_ICON} alt="★" className="ms-1 me-1" />
)}
<BreadcrumbTrail
modelType="Task"
leaf={task}
ascendantObjects={task.ascendantTasks}
parentField="parentTask"
/>
</React.Fragment>
))}
</span>
)}
</Col>
Expand Down
7 changes: 5 additions & 2 deletions client/src/components/SearchFilters.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ import {
LocationOverlayRow,
PersonDetailedOverlayRow,
PositionOverlayRow,
TaskSimpleOverlayRow
TaskOverlayRow
} from "components/advancedSelectWidget/AdvancedSelectOverlayRow"
import { getBreadcrumbTrailAsText } from "components/BreadcrumbTrail"
import Model from "components/Model"
import _isEmpty from "lodash/isEmpty"
import _pickBy from "lodash/pickBy"
Expand Down Expand Up @@ -168,9 +169,11 @@ const advancedSelectFilterLocationProps = {
}
const advancedSelectFilterTaskProps = {
overlayColumns: ["Name"],
overlayRenderRow: TaskSimpleOverlayRow,
overlayRenderRow: TaskOverlayRow,
objectType: Task,
valueKey: "shortName",
valueFunc: (v, k) =>
getBreadcrumbTrailAsText(v, v?.ascendantTasks, "parentTask", k),
fields: Task.autocompleteQuery,
addon: TASKS_ICON
}
Expand Down
Loading

0 comments on commit d0a9f63

Please sign in to comment.