Skip to content

Commit 47fae20

Browse files
authored
HP-1724 Feat/mixed avail icons (#1604)
* add mixed avail state and icon * add mixed avail icon * add new access descriptor * fix logic * fix words * update words * fix whitespace * update docs * address PR feedbacks * separate tooltip component
1 parent 0ce1345 commit 47fae20

File tree

10 files changed

+161
-106
lines changed

10 files changed

+161
-106
lines changed

docs/portal_config.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,8 @@ Below is an example, with inline comments describing what each JSON block config
513513
"menuText": "Not Accessible"
514514
},
515515
"waiting": {...},
516-
"notAvailable": {...}
516+
"notAvailable": {...},
517+
"mixed": {...} // this is a special state, it will only has effect if the "accessible" level has also been enabled. This state won't show up in the data access filter
517518
}
518519
},
519520
"tagsColumn" : {

src/Discovery/Discovery.test.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const initStoreData = {
2323
[AccessLevel.UNACCESSIBLE]: true,
2424
[AccessLevel.WAITING]: true,
2525
[AccessLevel.NOT_AVAILABLE]: true,
26+
[AccessLevel.MIXED]: true,
2627
},
2728
selectedTags: {},
2829
pagination: {

src/Discovery/Discovery.tsx

+22-77
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import React, {
55
import * as JsSearch from 'js-search';
66
import jsonpath from 'jsonpath';
77
import {
8-
Tag, Popover, Space, Collapse, Button, Dropdown, Pagination, Tooltip, Spin,
8+
Tag, Space, Collapse, Button, Dropdown, Pagination, Tooltip, Spin,
99
} from 'antd';
1010
import {
1111
LockOutlined,
@@ -35,6 +35,7 @@ import DiscoveryMDSSearch from './DiscoveryMDSSearch';
3535
import DiscoveryAccessibilityLinks from './DiscoveryAccessibilityLinks';
3636
import doSearchFilterSort from './Utils/Search/doSearchFilterSort';
3737
import './Discovery.css';
38+
import DiscoveryDataAvailabilityTooltips from './DiscoveryDataAvailabilityTooltips';
3839

3940
export const accessibleFieldName = '__accessible';
4041

@@ -44,6 +45,7 @@ export enum AccessLevel {
4445
WAITING = 3,
4546
NOT_AVAILABLE = 4,
4647
OTHER = 5,
48+
MIXED = 6,
4749
}
4850

4951
export enum AccessSortDirection {
@@ -52,8 +54,6 @@ export enum AccessSortDirection {
5254

5355
const { Panel } = Collapse;
5456

55-
const ARBORIST_READ_PRIV = 'read';
56-
5757
const setUpMenuItemInfo = (menuItemInfo, supportedValues) => {
5858
if (supportedValues?.waiting?.enabled === true) {
5959
menuItemInfo.push(
@@ -483,10 +483,20 @@ const Discovery: React.FunctionComponent<Props> = (props: Props) => {
483483
checked={props.accessFilters[accessLevel]}
484484
onChange={
485485
() => {
486-
props.onAccessFilterSet({
486+
const updatedAccessFilter = {
487487
...props.accessFilters,
488488
[accessLevel]: !props.accessFilters[accessLevel],
489-
});
489+
};
490+
// If "mixed availability" is enabled, set its value so it would show when either "accessible" or "unaccessible" is set
491+
const isMixedAvailabilityEnabled = config.features?.authorization?.supportedValues?.mixed?.enabled === true;
492+
const setMixedAvailabilityToShowWhenAccessibleOrUnaccessibleIsSet = () => {
493+
updatedAccessFilter[AccessLevel.MIXED] = Boolean(updatedAccessFilter[AccessLevel.ACCESSIBLE])
494+
|| Boolean(updatedAccessFilter[AccessLevel.UNACCESSIBLE]);
495+
};
496+
if (isMixedAvailabilityEnabled) {
497+
setMixedAvailabilityToShowWhenAccessibleOrUnaccessibleIsSet();
498+
}
499+
props.onAccessFilterSet(updatedAccessFilter);
490500
}
491501
}
492502
>
@@ -513,6 +523,7 @@ const Discovery: React.FunctionComponent<Props> = (props: Props) => {
513523
[AccessLevel.NOT_AVAILABLE]: true,
514524
[AccessLevel.WAITING]: true,
515525
[AccessLevel.UNACCESSIBLE]: true,
526+
[AccessLevel.MIXED]: true,
516527
},
517528
)}
518529
> Reset
@@ -578,78 +589,12 @@ const Discovery: React.FunctionComponent<Props> = (props: Props) => {
578589
ellipsis: false,
579590
width: '200px',
580591
textWrap: 'word-break',
581-
render: (_, record) => {
582-
if (record[accessibleFieldName] === AccessLevel.WAITING) {
583-
return (
584-
<Popover
585-
overlayClassName='discovery-popover'
586-
placement='topRight'
587-
arrowPointAtCenter
588-
content={(
589-
<div className='discovery-popover__text'>
590-
Data are not yet available for this study
591-
</div>
592-
)}
593-
>
594-
<ClockCircleOutlined className='discovery-table__access-icon' />
595-
</Popover>
596-
);
597-
}
598-
if (record[accessibleFieldName] === AccessLevel.NOT_AVAILABLE) {
599-
return (
600-
<Popover
601-
overlayClassName='discovery-popover'
602-
placement='topRight'
603-
arrowPointAtCenter
604-
content={(
605-
<div className='discovery-popover__text'>
606-
No data will be shared by this study
607-
</div>
608-
)}
609-
>
610-
<DashOutlined className='discovery-table__access-icon' />
611-
</Popover>
612-
);
613-
}
614-
if (record[accessibleFieldName] === AccessLevel.ACCESSIBLE) {
615-
return (
616-
<Popover
617-
overlayClassName='discovery-popover'
618-
placement='topRight'
619-
arrowPointAtCenter
620-
title={'You have access to these data.'}
621-
content={(
622-
<div className='discovery-popover__text'>
623-
<React.Fragment>You have <code>{ARBORIST_READ_PRIV}</code> access to </React.Fragment>
624-
<React.Fragment><code>{record[config.minimalFieldMapping.authzField]}</code>.</React.Fragment>
625-
</div>
626-
)}
627-
>
628-
<UnlockOutlined className='discovery-table__access-icon' />
629-
</Popover>
630-
);
631-
}
632-
if (record[accessibleFieldName] === AccessLevel.UNACCESSIBLE) {
633-
return (
634-
<Popover
635-
overlayClassName='discovery-popover'
636-
placement='topRight'
637-
arrowPointAtCenter
638-
title={'You do not currently have access to these data.'}
639-
content={(
640-
<div className='discovery-popover__text'>
641-
<React.Fragment>You don&apos;t have <code>{ARBORIST_READ_PRIV}</code> access to </React.Fragment>
642-
<React.Fragment><code>{record[config.minimalFieldMapping.authzField]}</code>. </React.Fragment>
643-
<React.Fragment>Visit the repository to request access to these data</React.Fragment>
644-
</div>
645-
)}
646-
>
647-
<LockOutlined className='discovery-table__access-icon' />
648-
</Popover>
649-
);
650-
}
651-
return <React.Fragment />;
652-
},
592+
render: (_, record) => (
593+
<DiscoveryDataAvailabilityTooltips
594+
dataAvailabilityLevel={record[accessibleFieldName]}
595+
authzFieldName={record[config.minimalFieldMapping.authzField]}
596+
/>
597+
),
653598
});
654599
}
655600
// -----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import {
2+
ClockCircleOutlined, DashOutlined, UnlockOutlined, LockOutlined,
3+
} from '@ant-design/icons';
4+
import { Popover } from 'antd';
5+
import React from 'react';
6+
import { AccessLevel } from './Discovery';
7+
8+
const ARBORIST_READ_PRIV = 'read';
9+
10+
interface Props {
11+
dataAvailabilityLevel: AccessLevel,
12+
authzFieldName: string
13+
}
14+
15+
const DiscoveryDataAvailabilityTooltips = (props: Props) => {
16+
if (props.dataAvailabilityLevel === AccessLevel.WAITING) {
17+
return (
18+
<Popover
19+
overlayClassName='discovery-popover'
20+
placement='topRight'
21+
arrowPointAtCenter
22+
content={(
23+
<div className='discovery-popover__text'>
24+
Data are not yet available for this study
25+
</div>
26+
)}
27+
>
28+
<ClockCircleOutlined className='discovery-table__access-icon' />
29+
</Popover>
30+
);
31+
}
32+
if (props.dataAvailabilityLevel === AccessLevel.NOT_AVAILABLE) {
33+
return (
34+
<Popover
35+
overlayClassName='discovery-popover'
36+
placement='topRight'
37+
arrowPointAtCenter
38+
content={(
39+
<div className='discovery-popover__text'>
40+
No data will be shared by this study
41+
</div>
42+
)}
43+
>
44+
<DashOutlined className='discovery-table__access-icon' />
45+
</Popover>
46+
);
47+
}
48+
if (props.dataAvailabilityLevel === AccessLevel.ACCESSIBLE) {
49+
return (
50+
<Popover
51+
overlayClassName='discovery-popover'
52+
placement='topRight'
53+
arrowPointAtCenter
54+
title={'You have access to these data.'}
55+
content={(
56+
<div className='discovery-popover__text'>
57+
<React.Fragment>You have <code>{ARBORIST_READ_PRIV}</code> access to </React.Fragment>
58+
<React.Fragment><code>{props.authzFieldName}</code>.</React.Fragment>
59+
</div>
60+
)}
61+
>
62+
<UnlockOutlined className='discovery-table__access-icon' />
63+
</Popover>
64+
);
65+
}
66+
if (props.dataAvailabilityLevel === AccessLevel.UNACCESSIBLE) {
67+
return (
68+
<Popover
69+
overlayClassName='discovery-popover'
70+
placement='topRight'
71+
arrowPointAtCenter
72+
title={'You do not currently have access to these data.'}
73+
content={(
74+
<div className='discovery-popover__text'>
75+
<React.Fragment>You don&apos;t have <code>{ARBORIST_READ_PRIV}</code> access to </React.Fragment>
76+
<React.Fragment><code>{props.authzFieldName}</code>. </React.Fragment>
77+
<React.Fragment>Visit the repository to request access to these data</React.Fragment>
78+
</div>
79+
)}
80+
>
81+
<LockOutlined className='discovery-table__access-icon' />
82+
</Popover>
83+
);
84+
}
85+
if (props.dataAvailabilityLevel === AccessLevel.MIXED) {
86+
return (
87+
<Popover
88+
overlayClassName='discovery-popover'
89+
placement='topRight'
90+
arrowPointAtCenter
91+
title={'You have access to some of these data.'}
92+
content={(
93+
<div className='discovery-popover__text'>
94+
<React.Fragment>Some of these data require visiting the repository to request access.</React.Fragment>
95+
</div>
96+
)}
97+
>
98+
<UnlockOutlined className='discovery-table__access-icon' />
99+
<LockOutlined className='discovery-table__access-icon' />
100+
</Popover>
101+
);
102+
}
103+
return <React.Fragment />;
104+
};
105+
106+
export default DiscoveryDataAvailabilityTooltips;

src/Discovery/DiscoveryDetails/Components/AccessDescriptor/AccessDescriptor.tsx

+18-8
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
11
import React from 'react';
22
import { Alert } from 'antd';
33
import { UnlockOutlined } from '@ant-design/icons';
4+
import { AccessLevel } from '../../../Discovery';
45

5-
interface NonTabbedDiscoveryDetailsProps {userHasAccess:boolean, userDoesNotHaveAccess:boolean}
6+
interface NonTabbedDiscoveryDetailsProps {accessibleFieldValue: AccessLevel}
67

7-
const AccessDescriptor = ({ userHasAccess, userDoesNotHaveAccess }: NonTabbedDiscoveryDetailsProps) => {
8-
if (userHasAccess) {
8+
const AccessDescriptor = ({ accessibleFieldValue }: NonTabbedDiscoveryDetailsProps) => {
9+
if (accessibleFieldValue === AccessLevel.ACCESSIBLE) {
910
return (
1011
<Alert
1112
className='discovery-modal__access-alert'
1213
type='success'
1314
message={(
1415
<React.Fragment>
15-
<UnlockOutlined /> You have access to this data.
16+
<UnlockOutlined />You have access to this data.
1617
</React.Fragment>
1718
)}
1819
/>
1920
);
2021
}
21-
if (userDoesNotHaveAccess) {
22+
if (accessibleFieldValue === AccessLevel.UNACCESSIBLE) {
2223
return (
2324
<Alert
2425
className='discovery-modal__access-alert'
@@ -29,14 +30,23 @@ const AccessDescriptor = ({ userHasAccess, userDoesNotHaveAccess }: NonTabbedDis
2930
/>
3031
);
3132
}
33+
if (accessibleFieldValue === AccessLevel.MIXED) {
34+
return (
35+
<Alert
36+
className='discovery-modal__access-alert'
37+
type='info'
38+
message={
39+
<React.Fragment>This study contains both open and restricted access data.</React.Fragment>
40+
}
41+
/>
42+
);
43+
}
3244
return (
3345
<Alert
3446
className='discovery-modal__access-alert'
3547
type='info'
3648
message={(
37-
<React.Fragment>
38-
This does not include data access authorization details.
39-
</React.Fragment>
49+
<React.Fragment>This does not include data access authorization details.</React.Fragment>
4050
)}
4151
/>
4252
);

src/Discovery/DiscoveryDetails/Components/FieldGrouping/TabField/TabField.tsx

+1-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import DataDownloadList from './DataDownloadList/DataDownloadList';
55
import {
66
renderFieldContent,
77
DiscoveryResource,
8-
AccessLevel,
98
accessibleFieldName,
109
} from '../../../../Discovery';
1110
import { User } from '../../../DiscoveryDetailsInterfaces';
@@ -28,12 +27,9 @@ const TabField = (
2827
): JSX.Element | null => {
2928
// Setup special fields first
3029
if (fieldConfig.type === 'accessDescriptor') {
31-
// return accessDescriptor(resource);
32-
// return AccessDescriptor(resource);
3330
return (
3431
<AccessDescriptor
35-
userHasAccess={resource[accessibleFieldName] === AccessLevel.ACCESSIBLE}
36-
userDoesNotHaveAccess={resource[accessibleFieldName] === AccessLevel.UNACCESSIBLE}
32+
accessibleFieldValue={resource[accessibleFieldName]}
3733
/>
3834
);
3935
}

src/Discovery/DiscoveryDetails/Components/NonTabbedDiscoveryDetails/NonTabbedDiscoveryDetails.tsx

+1-12
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { Button, Collapse, List } from 'antd';
33
import { DownloadOutlined } from '@ant-design/icons';
44
import jsonpath from 'jsonpath';
55
import {
6-
AccessLevel,
76
accessibleFieldName,
87
renderFieldContent,
98
} from '../../../Discovery';
@@ -15,15 +14,6 @@ import AccessDescriptor from '../AccessDescriptor/AccessDescriptor';
1514
const { Panel } = Collapse;
1615

1716
const NonTabbedDiscoveryDetails = ({ props }) => {
18-
const userHasAccess = props.config.features.authorization.enabled
19-
&& props.modalData[accessibleFieldName] !== AccessLevel.NOT_AVAILABLE
20-
&& props.modalData[accessibleFieldName] !== AccessLevel.WAITING
21-
&& props.modalData[accessibleFieldName] === AccessLevel.ACCESSIBLE;
22-
const userDoesNotHaveAccess = props.config.features.authorization.enabled
23-
&& props.modalData[accessibleFieldName] !== AccessLevel.NOT_AVAILABLE
24-
&& props.modalData[accessibleFieldName] !== AccessLevel.WAITING
25-
&& props.modalData[accessibleFieldName] !== AccessLevel.ACCESSIBLE;
26-
2717
const showDownloadPanel = props.config.studyPageFields.downloadLinks
2818
&& props.config.studyPageFields.downloadLinks.field
2919
&& props.modalData[props.config.studyPageFields.downloadLinks.field];
@@ -43,8 +33,7 @@ const NonTabbedDiscoveryDetails = ({ props }) => {
4333
<div className='discovery-modal-content'>
4434
<StudyHeader props={props} />
4535
<AccessDescriptor
46-
userHasAccess={userHasAccess}
47-
userDoesNotHaveAccess={userDoesNotHaveAccess}
36+
accessibleFieldValue={props.modalData[accessibleFieldName]}
4837
/>
4938
<div className='discovery-modal-attributes-container'>
5039
{props.config.studyPageFields.fieldsToShow.map(

src/Discovery/DiscoveryListView.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ const DiscoveryListView: React.FunctionComponent<Props> = (props: Props) => {
6969
let disabled;
7070
// if auth is enabled, disable checkbox if user doesn't have access
7171
if (props.config.features.authorization.enabled) {
72-
disabled = record[props.accessibleFieldName] !== AccessLevel.ACCESSIBLE;
72+
disabled = (record[props.accessibleFieldName] !== AccessLevel.ACCESSIBLE) && (record[props.accessibleFieldName] !== AccessLevel.MIXED);
7373
}
7474
// disable checkbox if there's no manifest or external file metadata (if metadata handoff is enabled) found for this study
7575
const exportToWorkspaceConfig = props.config.features.exportToWorkspace;

0 commit comments

Comments
 (0)