1 | import React, {PureComponent} from 'react';
|
2 | import PropTypes from 'prop-types';
|
3 | import servicesIcon from '@jetbrains/icons/services-20px.svg';
|
4 |
|
5 | import Dropdown from '../dropdown/dropdown';
|
6 | import Popup from '../popup/popup';
|
7 |
|
8 | import TrayIcon from './tray-icon';
|
9 | import ServicesLink from './services-link';
|
10 | import styles from './services.css';
|
11 |
|
12 | const makeAnchor = loading => {
|
13 | const Anchor = ({active}) => (
|
14 | <TrayIcon
|
15 | loader={loading}
|
16 | active={active}
|
17 | icon={servicesIcon}
|
18 | aria-label="Services"
|
19 | />
|
20 | );
|
21 |
|
22 | Anchor.propTypes = {
|
23 | active: PropTypes.bool
|
24 | };
|
25 |
|
26 | return Anchor;
|
27 | };
|
28 |
|
29 | export default class Services extends PureComponent {
|
30 | static Link = ServicesLink;
|
31 | static sort = (a, b) => {
|
32 | const aApplicationName = a.applicationName || '';
|
33 | const bApplicationName = b.applicationName || '';
|
34 |
|
35 | return aApplicationName.localeCompare(bApplicationName) ||
|
36 | a.name.localeCompare(b.name);
|
37 | };
|
38 |
|
39 | static propTypes = {
|
40 | className: PropTypes.string,
|
41 | clientId: PropTypes.string,
|
42 | initShown: PropTypes.bool,
|
43 | loading: PropTypes.bool,
|
44 | onClick: PropTypes.func,
|
45 | services: PropTypes.arrayOf(ServicesLink.propTypes.service)
|
46 | };
|
47 |
|
48 | serviceIsActive = service => service.id === this.props.clientId;
|
49 |
|
50 | render() {
|
51 |
|
52 | const {clientId, loading, services, initShown, ...props} = this.props;
|
53 |
|
54 | if (!services) {
|
55 | return (
|
56 | <TrayIcon
|
57 | {...props}
|
58 | loader={loading}
|
59 | active={loading}
|
60 | icon={servicesIcon}
|
61 | aria-label="Services"
|
62 | />
|
63 | );
|
64 | }
|
65 |
|
66 | const sortedServices = services.sort(Services.sort);
|
67 | const servicesWithIcons = sortedServices.filter(service => service.iconUrl);
|
68 | const servicesWithOutIcons = sortedServices.filter(service => !service.iconUrl);
|
69 | const separatorIsRequired = servicesWithIcons.length !== 0 && servicesWithOutIcons.length !== 0;
|
70 |
|
71 | return (
|
72 | <Dropdown
|
73 | {...props}
|
74 | anchor={makeAnchor(loading)}
|
75 | initShown={initShown}
|
76 | >
|
77 | <Popup
|
78 | className={styles.services}
|
79 | top={-3}
|
80 | >
|
81 | {servicesWithIcons.map(service => {
|
82 | const isActive = this.serviceIsActive(service);
|
83 |
|
84 | return (
|
85 | <Services.Link
|
86 | active={isActive}
|
87 | className={isActive ? styles.activeItem : styles.item}
|
88 | key={service.id}
|
89 | service={service}
|
90 | />
|
91 | );
|
92 | })}
|
93 | {separatorIsRequired && (
|
94 | <div
|
95 | className={styles.line}
|
96 | key="separator"
|
97 | />
|
98 | )}
|
99 | {servicesWithOutIcons.map(service => {
|
100 | const isActive = this.serviceIsActive(service);
|
101 |
|
102 | return (
|
103 | <Services.Link
|
104 | active={isActive}
|
105 | className={isActive ? styles.activeItemStacked : styles.itemStacked}
|
106 | key={service.id}
|
107 | service={service}
|
108 | />
|
109 | );
|
110 | })}
|
111 | </Popup>
|
112 | </Dropdown>
|
113 | );
|
114 | }
|
115 | }
|