• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ProteinsWebTeam / interpro7-client / 10298555325

08 Aug 2024 08:22AM UTC coverage: 25.376% (+2.5%) from 22.889%
10298555325

Pull #641

github

web-flow
Merge 8b67ca91f into 9398226d6
Pull Request #641: Re-factory of the Search By Sequence area

521 of 2519 branches covered (20.68%)

Branch coverage included in aggregate %.

7 of 9 new or added lines in 4 files covered. (77.78%)

6 existing lines in 2 files now uncovered.

1131 of 3991 relevant lines covered (28.34%)

92.24 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

21.11
/src/components/BreadCrumbs/index.js
1
import React from 'react';
2
import T from 'prop-types';
3
import { customLocationSelector } from 'reducers/custom-location';
4

5
import { connect } from 'react-redux';
6
import { createSelector } from 'reselect';
7

8
import Link from 'components/generic/Link';
9

10
import { foundationPartial } from 'styles/foundation';
11
import fonts from 'EBI-Icon-fonts/fonts.css';
12
import styles from './style.css';
13
import config from 'config';
14

15
const f = foundationPartial(fonts, styles);
1✔
16

17
/*::
18
  type Endpoint ={
19
    detail: string,
20
    db: string,
21
    accession: string,
22
    isFilter: boolean,
23
    order: number,
24
  }
25
  type SearchLocation = {
26
    type: string,
27
    value: string,
28
    accession: string,
29
    isFilter: boolean,
30
    order: number,
31
  }
32
  type Location = {
33
    main: {
34
      key: string,
35
      isFilter: boolean,
36
      order: number,
37
    },
38
    search: SearchLocation,
39
    result: SearchLocation,
40
    [string]: Endpoint,
41
    other: Array<string>,
42
  }
43
*/
44

45
const locationType = T.shape({
1✔
46
  main: T.shape({ key: T.string }),
47
  entry: T.shape({
48
    detail: T.string,
49
    db: T.string,
50
    accession: T.string,
51
    isFilter: T.bool,
52
    order: T.number,
53
  }),
54
  other: T.arrayOf(T.string),
55
});
56
const BreadCrumb = (
1✔
57
  { to, children } /*: {
58
    children: any,
59
    to?: function | {description: Object}} */,
60
) => {
61
  const childrenToPass =
62
    typeof children === 'string' ? children.replace(/_/g, ' ') : children;
×
63
  return (
×
64
    <span>
65
      {' / '}
66
      {to ? (
×
67
        <Link to={to} className={f('breadcrumb-link')}>
68
          {childrenToPass}
69
        </Link>
70
      ) : (
71
        childrenToPass
72
      )}{' '}
73
    </span>
74
  );
75
};
76
BreadCrumb.propTypes = {
1✔
77
  to: T.oneOfType([T.func, T.object]),
78
  children: T.any,
79
};
80

81
const BreadCrumbsForOther = ({ other } /*: { other: Array<string>} */) => {
1✔
82
  if (!other.length) return null;
×
83
  return (
×
84
    <section className={f('main')}>
85
      {other.map((part, i) => (
86
        <BreadCrumb
×
87
          key={i}
88
          to={{
89
            description: { other: other.slice(0, i + 1) },
90
          }}
91
        >
92
          {part}
93
        </BreadCrumb>
94
      ))}
95
    </section>
96
  );
97
};
98
BreadCrumbsForOther.propTypes = {
1✔
99
  other: T.arrayOf(T.string),
100
};
101

102
const BreadCrumbsForSearchOrResult = (
1✔
103
  { location } /*: {location: Location} */,
104
) => {
105
  if (!['search', 'result'].includes(location?.main?.key)) return null;
×
106
  // $FlowFixMe[incompatible-type]
107
  const key /*: 'search' | 'result' */ = location.main.key;
×
NEW
108
  const { type, value, job, accession } = location[key];
×
109
  return (
×
110
    <>
111
      <section className={f('main')}>
112
        <BreadCrumb to={{ description: { main: location.main } }}>
113
          {location.main.key}
114
        </BreadCrumb>
115
        <BreadCrumb
116
          to={{
117
            description: { main: location.main, [location.main.key]: { type } },
118
          }}
119
        >
120
          {type}
121
        </BreadCrumb>
122
        {job && (
×
123
          <BreadCrumb
124
            to={{
125
              description: {
126
                main: location.main,
127
                [location.main.key]: { type, job },
128
              },
129
            }}
130
          >
131
            {job}
132
          </BreadCrumb>
133
        )}
134
        {accession && (
×
135
          <BreadCrumb
136
            to={{
137
              description: {
138
                main: location.main,
139
                [location.main.key]: { type, job, accession },
140
              },
141
            }}
142
          >
143
            {accession}
144
          </BreadCrumb>
145
        )}
146
        {value && <BreadCrumb>{value}</BreadCrumb>}
×
147
      </section>
148
      {accession && <BreadCrumbForSecondPart location={location} />}
×
149
    </>
150
  );
151
};
152
BreadCrumbsForSearchOrResult.propTypes = {
1✔
153
  location: locationType,
154
};
155

156
const BreadCrumbForFilters = ({ location, filters }) => {
1✔
157
  return filters.map((ep) => {
×
158
    const { db, accession } = location[ep];
×
159
    return (
×
160
      <section className={f('filter')} key={ep}>
161
        <BreadCrumb
162
          to={{
163
            description: { ...location, [ep]: { db, isFilter: true } },
164
          }}
165
        >
166
          {ep}{' '}
167
        </BreadCrumb>
168
        <BreadCrumb
169
          to={{
170
            description: { ...location, [ep]: { db, isFilter: true } },
171
          }}
172
        >
173
          {db}
174
        </BreadCrumb>
175
        {accession && (
×
176
          <BreadCrumb
177
            to={{
178
              description: {
179
                ...location,
180
                [ep]: { db, accession, isFilter: true },
181
              },
182
            }}
183
          >
184
            {accession}
185
          </BreadCrumb>
186
        )}
187
      </section>
188
    );
189
  });
190
};
191
BreadCrumbForFilters.propTypes = {
1✔
192
  location: locationType,
193
  filters: T.arrayOf(T.string),
194
};
195

196
const BreadCrumbForEntityDetail = (
1✔
197
  {
198
    location,
199
    detail,
200
    filters = [],
×
201
  } /*: {location: Location, detail?: string, filters: Array<string>} */,
202
) => {
203
  const detailToRender = !filters.length && !detail ? ' Overview' : detail;
×
204
  return (
×
205
    <section className={f('detail')}>
206
      {detailToRender && (
×
207
        <BreadCrumb
208
          to={
209
            detail && {
×
210
              description: {
211
                ...location,
212
                [location.main.key]: {
213
                  ...location[location.main.key],
214
                  detail,
215
                },
216
              },
217
            }
218
          }
219
        >
220
          {detailToRender}
221
        </BreadCrumb>
222
      )}
223
      <BreadCrumbForFilters location={location} filters={filters} />
224
    </section>
225
  );
226
};
227
BreadCrumbForEntityDetail.propTypes = {
1✔
228
  location: locationType,
229
  filters: T.arrayOf(T.string),
230
  detail: T.string,
231
};
232

233
const BreadCrumbForSecondPart = ({ location } /*: {location: Location} */) => {
1✔
234
  const { accession, detail } = location[location.main.key];
×
235
  const filters = Object.keys(location)
×
236
    // $FlowFixMe[prop-missing]
237
    .filter((ep) => location[ep]?.isFilter)
×
238
    .sort(
239
      (ep1, ep2) =>
240
        // $FlowFixMe[prop-missing]
241
        location[ep1]?.order - location[ep2].order,
×
242
    );
243
  return (
×
244
    <section className={f('secondary')}>
245
      {accession ? (
×
246
        <BreadCrumbForEntityDetail
247
          location={location}
248
          detail={detail}
249
          filters={filters}
250
        />
251
      ) : (
252
        <BreadCrumbForFilters location={location} filters={filters} />
253
      )}
254
    </section>
255
  );
256
};
257
BreadCrumbForSecondPart.propTypes = {
1✔
258
  location: locationType,
259
};
260

261
const BreadCrumbsForBrowse = ({ location } /*: {location: Location} */) => {
1✔
262
  const endpoint = location?.main?.key;
×
263
  if (!config.endpoints.includes(endpoint)) return null;
×
264
  const { db, accession } = location[location.main.key];
×
265
  return (
×
266
    <>
267
      <section className={f('main')}>
268
        <BreadCrumb
269
          to={{
270
            description: { main: { key: 'entry' }, entry: { db: 'interpro' } },
271
          }}
272
        >
273
          Browse
274
        </BreadCrumb>
275
        <BreadCrumb
276
          to={{
277
            description: { main: { key: endpoint }, [endpoint]: { db } },
278
          }}
279
        >
280
          By{' '}
281
          {db && db.toLowerCase() === 'pfam' && endpoint.toLowerCase() === 'set'
×
282
            ? 'clan'
283
            : endpoint}{' '}
284
        </BreadCrumb>
285
        <BreadCrumb
286
          to={{
287
            description: { main: { key: endpoint }, [endpoint]: { db } },
288
          }}
289
        >
290
          {db}
291
        </BreadCrumb>
292
        {accession && (
×
293
          <BreadCrumb
294
            to={{
295
              description: {
296
                main: { key: endpoint },
297
                [endpoint]: { db, accession },
298
              },
299
            }}
300
          >
301
            {accession}{' '}
302
          </BreadCrumb>
303
        )}
304
      </section>
305
      <BreadCrumbForSecondPart location={location} />
306
    </>
307
  );
308
};
309
BreadCrumbsForBrowse.propTypes = {
1✔
310
  location: locationType,
311
};
312

313
const BreadCrumbs = (
1✔
314
  { location, hash } /*: {location: Location, hash: string} */,
315
) => {
316
  // Dont show if it is at home
317
  if (!location?.main?.key && !location?.other?.length) return null;
×
318
  return (
×
319
    <nav className={f('breadcrumbs')}>
320
      <Link to={{ description: {} }} className={f('breadcrumb-link')}>
321
        <span
322
          className={f('small', 'icon', 'icon-common')}
323
          data-icon="&#xf015;"
324
          aria-label={'Home'}
325
        />
326
      </Link>
327

328
      <BreadCrumbsForOther other={location?.other} />
329
      <BreadCrumbsForSearchOrResult location={location} />
330
      <BreadCrumbsForBrowse location={location} />
331
      {location?.main?.key === 'result' && hash?.startsWith('/') && (
×
332
        <BreadCrumb>API Download Form</BreadCrumb>
333
      )}
334
    </nav>
335
  );
336
};
337
BreadCrumbs.propTypes = {
1✔
338
  location: locationType,
339
  hash: T.string,
340
};
341

342
const mapStateToProps = createSelector(
1✔
343
  customLocationSelector,
344
  (customLocation) => ({
×
345
    location: customLocation.description,
346
    hash: customLocation.hash,
347
  }),
348
);
349

350
export default connect(mapStateToProps)(BreadCrumbs);
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc