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

mendersoftware / mender-server / 10423

11 Nov 2025 04:53PM UTC coverage: 74.435% (-0.1%) from 74.562%
10423

push

gitlab-ci

web-flow
Merge pull request #1071 from mendersoftware/dependabot/npm_and_yarn/frontend/main/development-dependencies-92732187be

3868 of 5393 branches covered (71.72%)

Branch coverage included in aggregate %.

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

176 existing lines in 95 files now uncovered.

64605 of 86597 relevant lines covered (74.6%)

7.74 hits per line

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

96.23
/frontend/src/js/common-ui/DocsLink.tsx
1
// Copyright 2023 Northern.tech AS
2✔
2
//
2✔
3
//    Licensed under the Apache License, Version 2.0 (the "License");
2✔
4
//    you may not use this file except in compliance with the License.
2✔
5
//    You may obtain a copy of the License at
2✔
6
//
2✔
7
//        http://www.apache.org/licenses/LICENSE-2.0
2✔
8
//
2✔
9
//    Unless required by applicable law or agreed to in writing, software
2✔
10
//    distributed under the License is distributed on an "AS IS" BASIS,
2✔
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2✔
12
//    See the License for the specific language governing permissions and
2✔
13
//    limitations under the License.
2✔
14
import { forwardRef, useState } from 'react';
2✔
15
import { useSelector } from 'react-redux';
2✔
16

2✔
17
import { Description as DescriptionIcon, Launch as LaunchIcon } from '@mui/icons-material';
2✔
18
import { Chip, Collapse, chipClasses } from '@mui/material';
2✔
19
import { makeStyles } from 'tss-react/mui';
2✔
20

2✔
21
import { TIMEOUTS } from '@northern.tech/store/constants';
2✔
22
import { getDocsVersion, getFeatures } from '@northern.tech/store/selectors';
2✔
23
import { useDebounce } from '@northern.tech/utils/debouncehook';
2✔
24

2✔
25
import { MenderTooltipClickable } from './helptips/MenderTooltip';
2✔
26

2✔
27
const useStyles = makeStyles()(theme => ({
87✔
28
  iconAura: {
2✔
29
    position: 'absolute',
2✔
30
    top: -6,
2✔
31
    bottom: -4,
2✔
32
    left: -7,
2✔
33
    right: -6.5,
2✔
34
    border: `1px dashed ${theme.palette.text.disabled}`,
2✔
35
    borderRadius: '50%',
2✔
36
    '&.hovering': {
2✔
37
      borderColor: 'transparent'
2✔
38
    }
2✔
39
  },
2✔
40
  chip: {
2✔
41
    borderStyle: 'dashed',
2✔
42
    [`.${chipClasses.deleteIcon}`]: {
2✔
43
      fontSize: 'smaller'
2✔
44
    },
2✔
45
    '&.not-hovering': {
2✔
46
      borderColor: 'transparent',
2✔
47
      color: theme.palette.text.disabled,
2✔
48
      [`.${chipClasses.deleteIcon}`]: {
2✔
49
        color: theme.palette.text.disabled
2✔
50
      },
2✔
51
      [`.${chipClasses.label}`]: {
2✔
52
        paddingLeft: 0,
2✔
53
        visibility: 'collapse'
2✔
54
      }
2✔
55
    }
2✔
56
  }
2✔
57
}));
2✔
58

2✔
59
export const DOCSTIPS = {
87✔
60
  deviceConfig: { id: 'deviceConfig', path: 'add-ons/configure' },
2✔
61
  dynamicGroups: { id: 'dynamicGroups', path: 'overview/device-group#dynamic-group' },
2✔
62
  limitedDeployments: { id: 'limitedDeployments', path: 'overview/deployment#deployment-to-dynamic-groups' },
2✔
63
  phasedDeployments: { id: 'phasedDeployments', path: 'overview/customize-the-update-process' },
2✔
64
  pausedDeployments: { id: 'pausedDeployments', path: 'overview/customize-the-update-process#synchronized-updates' },
2✔
65
  retryDeployments: { id: 'retryDeployments', path: 'overview/deployment' },
2✔
66
  releases: { id: 'releases', path: 'overview/artifact' },
2✔
67
  rbac: { id: 'rbac', path: 'overview/role.based.access.control' },
2✔
68
  webhookSecret: { id: 'webhookSecret', path: 'server-integration/webhooks#signature-header' }
2✔
69
};
2✔
70

2✔
71
export const DocsTooltip = ({ anchor = {}, id = '', ...props }) => {
87✔
72
  const [isHovering, setIsHovering] = useState(false);
628✔
73
  const debouncedHovering = useDebounce(isHovering, TIMEOUTS.debounceDefault);
628✔
74
  const docsVersion = useSelector(getDocsVersion);
628✔
75
  const { isHosted } = useSelector(getFeatures);
628✔
76
  const { classes } = useStyles();
628✔
77
  const { content, path } = DOCSTIPS[id] || {};
628!
78
  const target = `https://docs.mender.io/${docsVersion}${path}`;
628✔
79

2✔
80
  const onClick = () => {
628✔
81
    const docsParams = { headers: { 'x-mender-docs': docsVersion } };
2✔
82
    fetch(target, isHosted ? {} : docsParams);
2!
83
    window.open(target, '_blank');
2✔
84
  };
2✔
85

2✔
86
  const hoverClass = debouncedHovering ? 'hovering' : 'not-hovering';
628!
87
  return (
628✔
88
    <MenderTooltipClickable
2✔
89
      placement="bottom-start"
2✔
90
      disableFocusListener={false}
2✔
91
      disableHoverListener={false}
2✔
92
      disableTouchListener={false}
2✔
93
      style={anchor}
2✔
94
      title={content}
2✔
95
      {...props}
2✔
96
    >
2✔
97
      <Chip
2✔
98
        color="primary"
2✔
99
        className={`${classes.chip} ${hoverClass}`}
2✔
100
        label={
2✔
101
          <Collapse in={debouncedHovering} orientation="horizontal">
2✔
102
            Learn more
2✔
103
          </Collapse>
2✔
104
        }
2✔
105
        deleteIcon={
2✔
106
          <div className="relative">
2✔
107
            <DescriptionIcon fontSize="small" />
2✔
108
            <div className={`${classes.iconAura} ${hoverClass}`} />
2✔
109
          </div>
2✔
110
        }
2✔
111
        onClick={onClick}
2✔
112
        onDelete={onClick}
2✔
UNCOV
113
        onMouseOver={() => setIsHovering(true)}
2✔
UNCOV
114
        onMouseOut={() => setIsHovering(false)}
2✔
115
        variant="outlined"
2✔
116
      />
2✔
117
    </MenderTooltipClickable>
2✔
118
  );
2✔
119
};
2✔
120

2✔
121
export const InlineLaunchIcon = () => <LaunchIcon style={{ verticalAlign: 'sub' }} fontSize="small" />;
87✔
122

2✔
123
export const DocsLink = forwardRef(({ children, className = '', path, title = '', ...remainder }, ref) => {
87✔
124
  const docsVersion = useSelector(getDocsVersion);
183✔
125
  const { isHosted } = useSelector(getFeatures);
183✔
126
  const target = `https://docs.mender.io/${path}`;
183✔
127

2✔
128
  const onClickHandler = () => {
183✔
129
    const docsParams = { headers: { 'x-mender-docs': docsVersion } };
2✔
130
    fetch(target, isHosted ? {} : docsParams);
2!
131
  };
2✔
132

2✔
133
  return (
183✔
134
    // eslint-disable-next-line react/jsx-no-target-blank
2✔
135
    <a className={className} {...remainder} href={target} onClick={onClickHandler} ref={ref} target="_blank" rel={isHosted ? 'noopener' : ''}>
2✔
136
      {children ? children : title}
2✔
137
    </a>
2✔
138
  );
2✔
139
});
2✔
140

2✔
141
DocsLink.displayName = 'DocsLink';
87✔
142

2✔
143
export default DocsLink;
2✔
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