• 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

99.44
/frontend/src/js/components/releases/dialogs/ArtifactInformationForm.tsx
1
// Copyright 2020 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 { useEffect, useState } from 'react';
2✔
15
import { FormProvider, useForm } from 'react-hook-form';
2✔
16

2✔
17
import { FormControl, InputLabel, OutlinedInput, TextField, inputLabelClasses } from '@mui/material';
2✔
18
import { makeStyles } from 'tss-react/mui';
2✔
19

2✔
20
import ChipSelect from '@northern.tech/common-ui/ChipSelect';
2✔
21
import { DOCSTIPS, DocsTooltip } from '@northern.tech/common-ui/DocsLink';
2✔
22
import { InfoHintContainer } from '@northern.tech/common-ui/InfoHint';
2✔
23

2✔
24
import { HELPTOOLTIPS } from '../../helptips/HelpTooltips';
2✔
25
import { MenderHelpTooltip } from '../../helptips/MenderTooltip';
2✔
26
import { FileInformation } from './FileInformation';
2✔
27

2✔
28
const defaultVersion = '1.0.0';
8✔
29

2✔
30
const useStyles = makeStyles()(theme => ({
8✔
31
  formWrapper: { display: 'flex', flexDirection: 'column', gap: theme.spacing(2) },
2✔
32
  releaseName: {
2✔
33
    display: 'flex',
2✔
34
    alignItems: 'center',
2✔
35
    [`&.${inputLabelClasses.shrink}`]: {
2✔
36
      background: theme.palette.background.default,
2✔
37
      paddingLeft: theme.spacing(0.5),
2✔
38
      paddingRight: theme.spacing(),
2✔
39
      marginTop: theme.spacing(-0.5)
2✔
40
    }
2✔
41
  }
2✔
42
}));
2✔
43

2✔
44
export const VersionInformation = ({ creation = {}, onRemove, updateCreation }) => {
8✔
45
  const { file, fileSystem: propFs, name, softwareName: propName, softwareVersion: version = '', type } = creation;
4✔
46
  const [fileSystem, setFileSystem] = useState(propFs);
4✔
47
  const [softwareName, setSoftwareName] = useState(propName || name.replace('.', '-'));
4✔
48
  const [softwareVersion, setSoftwareVersion] = useState(version || defaultVersion);
4✔
49
  const { classes } = useStyles();
4✔
50

2✔
51
  useEffect(() => {
4✔
52
    updateCreation({ finalStep: true });
3✔
53
  }, [updateCreation]);
2✔
54

2✔
55
  useEffect(() => {
4✔
56
    updateCreation({ fileSystem, softwareName, softwareVersion, isValid: fileSystem && softwareName && softwareVersion });
3✔
57
  }, [fileSystem, softwareName, softwareVersion, updateCreation]);
2✔
58

2✔
59
  return (
4✔
60
    <>
2✔
61
      <FileInformation file={file} type={type} onRemove={onRemove} />
2✔
62
      <h4>Version information</h4>
2✔
63
      <div className={classes.formWrapper}>
2✔
64
        {[
2✔
65
          { key: 'fileSystem', title: 'Software filesystem', setter: setFileSystem, value: fileSystem },
2✔
66
          { key: 'softwareName', title: 'Software name', setter: setSoftwareName, value: softwareName },
2✔
67
          { key: 'softwareVersion', title: 'Software version', setter: setSoftwareVersion, value: softwareVersion }
2✔
68
        ].map(({ key, title, setter, value: currentValue }, index) => (
2✔
69
          <TextField autoFocus={!index} fullWidth key={key} label={title} onChange={({ target: { value } }) => setter(value)} value={currentValue} />
8✔
70
        ))}
2✔
71
      </div>
2✔
72
    </>
2✔
73
  );
2✔
74
};
2✔
75

2✔
76
const checkDestinationValidity = destination => (destination.length ? /^(?:\/|[a-z]+:\/\/)/.test(destination) : false);
147✔
77

2✔
78
export const ArtifactInformation = ({ creation = {}, deviceTypes = [], onRemove, updateCreation }) => {
8✔
79
  const { destination = '', file, name = '', selectedDeviceTypes = [], type } = creation;
92✔
80

2✔
81
  const methods = useForm({ mode: 'onChange', defaultValues: { deviceTypes: selectedDeviceTypes } });
92✔
82
  const { watch } = methods;
92✔
83
  const formDeviceTypes = watch('deviceTypes');
92✔
84
  const { classes } = useStyles();
92✔
85

2✔
86
  useEffect(() => {
92✔
87
    updateCreation({ selectedDeviceTypes: formDeviceTypes });
16✔
88
  }, [formDeviceTypes, updateCreation]);
2✔
89

2✔
90
  useEffect(() => {
92✔
91
    updateCreation({
37✔
92
      destination,
2✔
93
      isValid: checkDestinationValidity(destination) && selectedDeviceTypes.length && name,
2✔
94
      finalStep: false
2✔
95
    });
2✔
96
  }, [destination, name, selectedDeviceTypes.length, updateCreation]);
2✔
97

2✔
98
  const onDestinationChange = ({ target: { value } }) =>
92✔
99
    updateCreation({ destination: value, isValid: checkDestinationValidity(value) && selectedDeviceTypes.length && name });
22!
100

2✔
101
  const isValidDestination = checkDestinationValidity(destination);
92✔
102
  return (
92✔
103
    <div className="flexbox column" style={{ gap: 15 }}>
2✔
104
      <FileInformation file={file} type={type} onRemove={onRemove} />
2✔
105
      <TextField
2✔
106
        autoFocus={true}
2✔
107
        error={!isValidDestination}
2✔
108
        fullWidth
2✔
109
        helperText={
2✔
110
          !isValidDestination ? <span className="warning">Destination has to be an absolute path</span> : 'where the file will be installed on your devices'
2✔
111
        }
2✔
112
        label="Destination directory"
2✔
113
        onChange={onDestinationChange}
2✔
114
        placeholder="Example: /opt/installed-by-single-file"
2✔
115
        value={destination}
2✔
116
      />
2✔
117
      <h4>Artifact information</h4>
2✔
118
      <FormControl>
2✔
UNCOV
119
        <InputLabel htmlFor="release-name" className={classes.releaseName} onClick={e => e.preventDefault()}>
2✔
120
          Release name
2✔
121
          <InfoHintContainer>
2✔
122
            <MenderHelpTooltip id={HELPTOOLTIPS.releaseName.id} />
2✔
123
            <DocsTooltip id={DOCSTIPS.releases.id} />
2✔
124
          </InfoHintContainer>
2✔
125
        </InputLabel>
2✔
126
        <OutlinedInput
2✔
127
          defaultValue={name}
2✔
128
          className="release-name-input"
2✔
129
          id="release-name"
2✔
130
          placeholder="A descriptive name for the software"
2✔
131
          onChange={e => updateCreation({ name: e.target.value })}
14✔
132
        />
2✔
133
      </FormControl>
2✔
134
      <FormProvider {...methods}>
2✔
135
        <form noValidate>
2✔
136
          <ChipSelect
2✔
137
            name="deviceTypes"
2✔
138
            label="Device types compatible"
2✔
139
            helperText="Enter all device types this software is compatible with"
2✔
140
            options={deviceTypes}
2✔
141
          />
2✔
142
        </form>
2✔
143
      </FormProvider>
2✔
144
    </div>
2✔
145
  );
2✔
146
};
2✔
147

2✔
148
const steps = [ArtifactInformation, VersionInformation];
8✔
149

2✔
150
export const ArtifactInformationForm = ({ activeStep, ...remainder }) => {
8✔
151
  const Component = steps[activeStep];
83✔
152
  return <Component {...remainder} />;
83✔
153
};
2✔
154

2✔
155
export default ArtifactInformationForm;
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