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

mendersoftware / mender-server / 1539946168

13 Nov 2024 09:11AM UTC coverage: 72.77% (+0.03%) from 72.743%
1539946168

push

gitlab-ci

web-flow
Merge pull request #191 from mzedel/MEN-7570

MEN-7570 - SP RBAC + ensured linter runs on all TS files

4170 of 6064 branches covered (68.77%)

Branch coverage included in aggregate %.

182 of 199 new or added lines in 18 files covered. (91.46%)

2 existing lines in 1 file now uncovered.

42469 of 58027 relevant lines covered (73.19%)

16.79 hits per line

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

89.39
/frontend/src/js/components/settings/role-management/PermissionsSelect.tsx
1
// Copyright 2024 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 { FunctionComponent, useMemo } from 'react';
15
import { Controller, useFormContext } from 'react-hook-form';
16

17
import { Checkbox, FormControl, InputLabel, MenuItem, PopoverProps, Select } from '@mui/material';
18
import { makeStyles } from 'tss-react/mui';
19

20
import { PermissionsArea, UiPermission, uiPermissionsById } from '@northern.tech/store/constants';
21

22
const menuProps: Partial<PopoverProps> = {
5✔
23
  anchorOrigin: {
24
    vertical: 'bottom',
25
    horizontal: 'left'
26
  },
27
  transformOrigin: {
28
    vertical: 'top',
29
    horizontal: 'left'
30
  }
31
};
32

33
const useStyles = makeStyles()(theme => ({
25✔
34
  permissionSelect: { marginLeft: theme.spacing(-1.5) }
35
}));
36

37
const permissionEnabledDisabled = (uiPermission, selectedUiPermissions, permissionsArea, unscoped) => {
5✔
38
  const { permissionLevel, value: permissionValue, unscopedOnly = {} } = uiPermission;
664✔
39
  const disabled = selectedUiPermissions.some(permission => uiPermissionsById[permission].permissionLevel > permissionLevel);
664✔
40
  const enabled = selectedUiPermissions.some(permission => permission === permissionValue) || disabled;
664✔
41
  const skip = unscopedOnly[permissionsArea] && !unscoped;
664!
42
  return { enabled, disabled, skip };
664✔
43
};
44

45
const renderSelectionValues = (options, selectedValues, permissionsArea, unscoped) => {
5✔
46
  if (!selectedValues.length) {
282✔
47
    return 'None';
152✔
48
  }
49
  return options
130✔
50
    .reduce((accu, uiPermission) => {
51
      const { enabled } = permissionEnabledDisabled(uiPermission, selectedValues, permissionsArea, unscoped);
530✔
52
      if (enabled) {
530✔
53
        accu.push(uiPermission.title);
140✔
54
      }
55
      return accu;
530✔
56
    }, [])
57
    .join(', ');
58
};
59

60
export interface PermissionsSelectionBaseProps {
61
  disabled: boolean;
62
}
63

64
interface IPermissionsSelect extends PermissionsSelectionBaseProps {
65
  label?: string;
66
  onChange?: (string) => void;
67
  options: UiPermission[];
68
  name?: string;
69
  permissionsArea: PermissionsArea;
70
  unscoped?: boolean;
71
}
72

73
type EditableUiPermission = UiPermission & {
74
  enabled: boolean;
75
  disabled: boolean;
76
};
77

78
export const PermissionsSelect: FunctionComponent<IPermissionsSelect> = ({
5✔
79
  disabled,
80
  label = '',
144✔
81
  onChange,
82
  options,
83
  name = '',
144✔
84
  permissionsArea,
85
  unscoped = false
144✔
86
}) => {
87
  const { control, getValues } = useFormContext();
410✔
88
  const { classes } = useStyles();
410✔
89
  const selectedUiPermissions = name ? getValues(name) : getValues(permissionsArea.key);
410✔
90

91
  const onInputChange =
92
    setter =>
410✔
93
    ({ target: { value } }) => {
418✔
94
      if (value.includes('')) {
4!
NEW
95
        return setter([]);
×
96
      }
97
      if (onChange) {
4!
98
        return onChange(value);
4✔
99
      }
NEW
100
      return setter(value);
×
101
    };
102

103
  const editablePermissions = useMemo(
410✔
104
    () =>
105
      options.reduce<EditableUiPermission[]>((accu, uiPermission) => {
43✔
106
        const { enabled, disabled, skip } = permissionEnabledDisabled(uiPermission, selectedUiPermissions, permissionsArea, unscoped);
134✔
107
        if (skip) {
134!
NEW
108
          return accu;
×
109
        }
110
        accu.push({ enabled, disabled, ...uiPermission });
134✔
111
        return accu;
134✔
112
      }, []),
113
    [options, permissionsArea, unscoped, selectedUiPermissions]
114
  );
115

116
  return (
410✔
117
    <FormControl>
118
      <InputLabel id="permission-selection-label">{label && !selectedUiPermissions.length ? label : ''}</InputLabel>
1,086✔
119
      <Controller
120
        name={name || permissionsArea.key}
554✔
121
        control={control}
122
        render={({ field }) => (
123
          <Select
418✔
124
            labelId="permission-selection-label"
125
            disabled={disabled}
126
            displayEmpty={!label}
127
            fullWidth
128
            MenuProps={menuProps}
129
            multiple
130
            renderValue={selection => renderSelectionValues(options, selection, permissionsArea, unscoped)}
282✔
131
            {...field}
132
            onChange={onInputChange(field.onChange)}
133
          >
134
            {editablePermissions.map(uiPermission => (
135
              <MenuItem disabled={uiPermission.disabled} key={uiPermission.value} value={uiPermission.value}>
1,302✔
136
                <Checkbox className={classes.permissionSelect} checked={uiPermission.enabled} disabled={uiPermission.disabled} />
137
                <div className={uiPermission.disabled ? 'text-muted' : ''}>{uiPermission.title}</div>
1,302✔
138
              </MenuItem>
139
            ))}
140
            <MenuItem value="">None</MenuItem>
141
          </Select>
142
        )}
143
      />
144
    </FormControl>
145
  );
146
};
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