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

zooniverse / Panoptes-Front-End / 21962335028

12 Feb 2026 08:04PM UTC coverage: 55.977% (-0.02%) from 55.996%
21962335028

push

github

web-flow
Refactor GeoDrawing editor with color and uncertainty_circle options (#7402)

* Refactor GeoDrawing editor with color and uncertainty_circle options

* Create toolColors constant, update generic-editor and Pages Editor DrawingTool

7202 of 13250 branches covered (54.35%)

Branch coverage included in aggregate %.

3 of 5 new or added lines in 2 files covered. (60.0%)

91 existing lines in 2 files now uncovered.

8265 of 14381 relevant lines covered (57.47%)

100.48 hits per line

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

84.96
/app/pages/project/components/ProjectNavbar/ProjectNavbarContainer.jsx
1
import _ from 'lodash';
1✔
2
import counterpart from 'counterpart';
1✔
3
import React, { Component } from 'react';
1✔
4
import PropTypes from 'prop-types';
1✔
5
import apiClient from 'panoptes-client/lib/api-client';
1✔
6
import isAdmin from '../../../../lib/is-admin';
1✔
7
import { monorepoURL, usesPFEClassifier } from '../../../../monorepoUtils';
1✔
8

9
import { getProjectLinks } from '../../../../lib/nav-helpers';
1✔
10
import ProjectNavbar from './ProjectNavbar';
114✔
11

12
function isResourceAProject(resource) {
13
  return Object.keys(resource).includes('workflow_description');
6✔
14
}
15

16
class ProjectNavbarContainer extends Component {
1✔
17
  constructor(props) {
3✔
18
    super(props);
3✔
19

20
    this.state = {
3✔
21
      adminEnabled: false
22
    };
3✔
23
  }
1✔
24

25
  componentDidMount() {
26
    apiClient.listen('change', this.handleClientChange.bind(this));
3✔
27
  }
28

29
  componentWillUnmount() {
30
    apiClient.stopListening('change', this.handleClientChange.bind(this));
1✔
31
  }
32

33
  getNavLinks() {
34
    const project = this.getProjectLinks();
3✔
35
    const org = this.getOrganizationLink();
3✔
36
    return [].concat(project, org);
3✔
37
  }
38

39
  getOrganizationLink() {
40
    const { organization } = this.props;
3✔
41
    const link = [];
3✔
42

43
    if (organization) {
3✔
44
      link.push({
1✔
45
        label: organization.display_name,
46
        url: `/organizations/${organization.slug}`
47
      });
48
    }
49

50
    return link;
3✔
51
  }
52

53
  getProjectLinks() {
54
    const { project, projectRoles, user } = this.props;
3✔
55
    const links = getProjectLinks({ project, projectRoles, user });
3✔
56

57
    return _.map(links, link => ({
13✔
58
      disabled: link.disabled || false,
23✔
59
      isExternalLink: link.isExternalLink || false,
26✔
60
      isMonorepoLink: link.isMonorepoLink || false,
20✔
61
      label: counterpart(link.translationPath),
62
      url: link.url
63
    }));
64
  }
65

66

67
  handleClientChange() {
UNCOV
68
    const adminEnabled = isAdmin();
×
UNCOV
69
    if (adminEnabled !== this.state.adminEnabled) {
×
70
      // Trigger a re-render if an admin user toggles the admin mode checkbox
71
      this.setState({ adminEnabled });
×
72
    }
73
  }
74

75
  render() {
76
    const searchParams = new URLSearchParams(window.location.search);
3✔
77
    const env = searchParams.get('env');
3✔
78
    const locale = counterpart.getLocale();
3✔
79
    const newSearchParams = new URLSearchParams();
3✔
80

81
    // For most projects, primary_language is en
82
    if (locale !== this.props.project.primary_language) {
3!
83
      newSearchParams.set('language', locale);
3✔
84
    }
85

86
    if (env) {
3!
87
      newSearchParams.set('env', env);
×
88
    }
89

90
    const query = `${newSearchParams}` ? `?${newSearchParams}` : '';
3!
91
    const avatarSrc = _.get(this.props.projectAvatar, 'src', undefined);
3✔
92
    const backgroundSrc = _.get(this.props.background, 'src', undefined);
3✔
93
    const launched = this.props.project.launch_approved || this.props.project.listed;
3✔
94
    const navLinks = isResourceAProject(this.props.project) ? this.getNavLinks() : [];
3!
95
    const projectTitle = _.get(this.props.translation, 'display_name', undefined);
3✔
96
    const projectLink = isResourceAProject(this.props.project) ? `/projects/${this.props.project.slug}${query}` : `/organizations/${this.props.project.slug}${query}`;
3!
97
    const underReview = this.props.project.beta_approved;
3✔
98
    const hasExternalFrontend = !!this.props.project.redirect
3✔
99
    let redirect = this.props.project.redirect ? this.props.project.redirect : '';
3!
100

101
    /**
102
      Unless a project is whitelisted to stay on PFE's classiifer, the link to a project's homepage
103
      about pages, or classify page should go to FEM which expects locale to formatted as
104
      /projects/locale/owner/projectName
105
     */
106
    if (!usesPFEClassifier(this.props.project.slug)) {
3!
107
      const i18nSlug = locale === 'en' ? this.props.project.slug : `${locale}/${this.props.project.slug}`;
3!
108
      const envQuery = env === 'staging' ? '?env=staging' : '';
3!
109
      redirect = `${monorepoURL(i18nSlug)}${envQuery}`;
3✔
110
    }
111

112
    return (
3✔
113
      <ProjectNavbar
114
        avatarSrc={avatarSrc}
115
        backgroundSrc={backgroundSrc}
116
        hasExternalFrontend={hasExternalFrontend}
117
        launched={launched}
118
        navLinks={navLinks}
119
        project={this.props.project}
120
        projectTitle={projectTitle}
121
        projectLink={projectLink}
122
        redirect={redirect}
123
        underReview={underReview}
124
        usesPFEClassifier={usesPFEClassifier(this.props.project.slug)}
125
      />
126
    );
127
  }
1✔
128
}
129

130
ProjectNavbarContainer.propTypes = {
1✔
131
  background: PropTypes.shape({
132
    src: PropTypes.string
133
  }),
134
  organization: PropTypes.shape({
135
    display_name: PropTypes.string,
136
    slug: PropTypes.string
137
  }),
138
  projectAvatar: PropTypes.shape({
139
    src: PropTypes.string
140
  }),
141
  project: PropTypes.shape({
142
    beta_approved: PropTypes.bool,
143
    launch_approved: PropTypes.bool,
144
    redirect: PropTypes.string,
145
    slug: PropTypes.string,
146
    title: PropTypes.string,
147
    urls: PropTypes.array
148
  }),
149
  projectRoles: PropTypes.array,
150
  translation: PropTypes.shape({
151
    display_name: PropTypes.string
152
  }),
153
  user: PropTypes.object
154
};
1,365!
155

156
export default ProjectNavbarContainer;
17!
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

© 2026 Coveralls, Inc