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

mendersoftware / mender-server / 1568834739

02 Dec 2024 10:01AM UTC coverage: 73.562% (+0.8%) from 72.786%
1568834739

Pull #211

gitlab-ci

mineralsfree
test: added upgrade unit tests

Ticket: MEN-7469
Changelog: None

Signed-off-by: Mikita Pilinka <mikita.pilinka@northern.tech>
Pull Request #211: MEN-7469-feat: updated upgrades and add-on page

4251 of 6156 branches covered (69.05%)

Branch coverage included in aggregate %.

166 of 200 new or added lines in 18 files covered. (83.0%)

47 existing lines in 4 files now uncovered.

40029 of 54038 relevant lines covered (74.08%)

17.83 hits per line

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

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

16
import { Check as CheckIcon, DeveloperBoard as DeveloperBoardIcon } from '@mui/icons-material';
17
import { Button } from '@mui/material';
18
import { makeStyles } from 'tss-react/mui';
19

20
import { AvailablePlans, PLANS, Plan } from '@northern.tech/store/constants';
21
import { isEmpty } from '@northern.tech/utils/helpers';
22

23
import { clearLocalStorageEntry, isUpgrade } from './Upgrade';
24

25
const useStyles = makeStyles()(theme => ({
6✔
26
  planIcon: { color: theme.palette.primary.main, fontSize: '16px' },
27
  planFeature: { fontSize: '12px' },
28
  planButton: { alignSelf: 'center' },
29
  planPanel: {
30
    padding: '22px 16px',
31
    borderRadius: '5px',
32
    verticalAlign: 'top',
33
    width: '32%',
34
    transition: 'all 0.2s ease',
35
    cursor: 'pointer',
36
    display: 'flex',
37
    flexDirection: 'column',
38
    justifyContent: 'space-between',
39
    marginRight: theme.spacing(2),
40
    border: `1px solid ${theme.palette.grey[600]}`,
41
    fontSize: '14px',
42
    fontWeight: 500,
43
    '&.muted, &.muted:hover': {
44
      cursor: 'default',
45
      boxShadow: 'none'
46
    }
47
  }
48
}));
49

50
const isPlanDisabled = (item: Plan, currentPlan: AvailablePlans, isTrial: boolean, isUpgradePending: Partial<{ plan: AvailablePlans }>) => {
6✔
51
  return (
51✔
52
    (item.id === currentPlan && !isTrial) ||
178!
53
    (isUpgradePending && item.id === isUpgradePending.plan) ||
54
    (currentPlan === PLANS.professional.id && item.id === PLANS.os.id)
55
  );
56
};
57

58
export const PlanSelection = ({ orgId, currentPlan = PLANS.os.id, isTrial, setUpdatedPlan, updatedPlan }) => {
6✔
59
  const { classes } = useStyles();
17✔
60
  const canUpgrade = (plan: AvailablePlans) => Object.keys(PLANS).indexOf(plan) >= Object.keys(PLANS).indexOf(currentPlan);
44✔
61
  const onPlanSelect = (plan: AvailablePlans) => (isTrial || canUpgrade(plan) ? setUpdatedPlan(plan) : undefined);
17!
62
  const isUpgradePending = isUpgrade(orgId);
17✔
63

64
  useEffect(() => {
17✔
65
    if (!isEmpty(isUpgradePending) && currentPlan === isUpgradePending.plan) {
17!
NEW
66
      clearLocalStorageEntry(orgId, isUpgradePending.plan);
×
67
    }
68
  }, [currentPlan, isUpgradePending, orgId]);
69
  const getPlanButtonLabel = (planId: AvailablePlans) => {
17✔
70
    if (!isEmpty(isUpgradePending) && isUpgradePending.plan === planId) return 'pending';
51✔
71
    if (isTrial) return planId === PLANS.enterprise.id ? 'contact us' : 'subscribe';
50✔
72
    if (currentPlan === planId) return 'current plan';
41✔
73
    return planId === PLANS.enterprise.id ? 'contact us' : 'upgrade';
27✔
74
  };
75

76
  return (
17✔
77
    <>
78
      <p className="margin-top">Your current plan: {isTrial ? ' Free trial' : `Mender ${PLANS[currentPlan].name}`}</p>
17✔
79
      <div className="flexbox margin-bottom-small">
80
        {Object.values(PLANS).map(item => (
81
          <div
51✔
82
            key={item.id}
83
            className={`planPanel ${classes.planPanel} ${updatedPlan === item.id ? 'active' : ''} ${isTrial || canUpgrade(item.id) ? '' : 'muted'}`}
195!
84
          >
85
            <div>
86
              <p className="margin-none">Mender {item.name}</p>
87
              <h2>{item.price}</h2>
88
              <div className="margin-bottom">
89
                <div className="flexbox align-center">
90
                  <DeveloperBoardIcon fontSize="medium" className={`${classes.planIcon}`} />
91
                  <div className="margin-left-x-small">
92
                    {item.deviceCount}
93
                    {item.id === PLANS.enterprise.id ? '' : '*'}
51✔
94
                  </div>
95
                </div>
96
              </div>
97
              <ul className="unstyled">
98
                {item.features.map((feature, index) => (
99
                  <li className={`flexbox margin-bottom-x-small ${classes.planFeature}`} key={`${item.id}-feature-${index}`}>
119✔
100
                    <CheckIcon className={classes.planIcon} />
101
                    <div className="margin-left-x-small">{feature}</div>{' '}
102
                  </li>
103
                ))}
104
              </ul>
105
            </div>
106
            <Button
107
              onClick={() => onPlanSelect(item.id)}
3✔
108
              variant="contained"
109
              color={item.id === PLANS.enterprise.id ? 'secondary' : 'primary'}
51✔
110
              disabled={isPlanDisabled(item, currentPlan, isTrial, isUpgradePending)}
111
            >
112
              {getPlanButtonLabel(item.id)}
113
            </Button>
114
          </div>
115
        ))}
116
      </div>
117
    </>
118
  );
119
};
120

121
export default PlanSelection;
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