• 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

97.94
/frontend/src/js/components/settings/organization/SSOEditor.tsx
1
// Copyright 2022 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 { useCallback, useEffect, useRef, useState } from 'react';
2✔
15
import Dropzone from 'react-dropzone';
2✔
16

2✔
17
// material ui
2✔
18
import { CloudUpload, FileCopyOutlined as CopyPasteIcon } from '@mui/icons-material';
2✔
19
import { Button, Divider, Drawer } from '@mui/material';
2✔
20

2✔
21
import Editor, { loader } from '@monaco-editor/react';
2✔
22
import { DrawerTitle } from '@northern.tech/common-ui/DrawerTitle';
2✔
23
import Loader from '@northern.tech/common-ui/Loader';
2✔
24
import { JSON_METADATA_FORMAT, XML_METADATA_FORMAT } from '@northern.tech/store/constants';
2✔
25
import { createFileDownload } from '@northern.tech/utils/helpers';
2✔
26
import copy from 'copy-to-clipboard';
2✔
27

2✔
28
loader.config({ paths: { vs: '/ui/vs' } });
9✔
29

2✔
30
const editorProps = {
9✔
31
  height: 700,
2✔
32
  loading: <Loader show />,
2✔
33
  options: {
2✔
34
    autoClosingOvertype: 'auto',
2✔
35
    codeLens: false,
2✔
36
    contextmenu: false,
2✔
37
    enableSplitViewResizing: false,
2✔
38
    formatOnPaste: true,
2✔
39
    lightbulb: { enabled: false },
2✔
40
    lineNumbers: 'off',
2✔
41
    minimap: { enabled: false },
2✔
42
    quickSuggestions: false,
2✔
43
    readOnly: true,
2✔
44
    renderOverviewRuler: false,
2✔
45
    scrollBeyondLastLine: false,
2✔
46
    wordWrap: 'on'
2✔
47
  }
2✔
48
};
2✔
49

2✔
50
export const SSOEditor = ({ ssoItem, config, fileContent, hasSSOConfig, open, onCancel, onClose, onSave, setFileContent, token }) => {
9✔
51
  const [isEditing, setIsEditing] = useState(false);
14✔
52
  const [isMetadataValid, setIsMetadataValid] = useState(false);
14✔
53
  const editorRef = useRef();
14✔
54

2✔
55
  useEffect(() => {
14✔
56
    if (!fileContent) {
8✔
57
      return;
4✔
58
    }
2✔
59

2✔
60
    const parser = new DOMParser();
6✔
61
    let valid = false;
6✔
62
    switch (ssoItem.metadataFormat) {
6✔
63
      case JSON_METADATA_FORMAT:
2✔
64
        try {
4✔
65
          JSON.parse(fileContent);
4✔
66
          valid = true;
4✔
67
        } catch {
2✔
68
          valid = false;
2✔
69
        }
2✔
70
        break;
4✔
71
      case XML_METADATA_FORMAT:
2✔
72
      default:
2✔
73
        valid = !parser.parseFromString(fileContent, 'application/xml').getElementsByTagName('parsererror').length;
4✔
74
        break;
4✔
75
    }
2✔
76
    setIsMetadataValid(valid);
6✔
77
  }, [fileContent, ssoItem.metadataFormat]);
2✔
78

2✔
79
  const onEditClick = () => setIsEditing(true);
14✔
80

2✔
UNCOV
81
  const onDownloadClick = () => createFileDownload(fileContent, `metadata.${ssoItem.metadataFormat}`, token);
2✔
82

2✔
83
  const onCancelClick = useCallback(() => {
14✔
84
    if (isEditing) {
2!
85
      setFileContent(config);
2✔
86
      if (!hasSSOConfig) {
2!
87
        return onCancel();
2✔
88
      }
2✔
89
      return setIsEditing(false);
2✔
90
    }
2✔
91
    onClose();
2✔
92
  }, [config, hasSSOConfig, isEditing, onCancel, setFileContent, onClose]);
2✔
93

2✔
94
  const onSubmitClick = () => {
14✔
95
    onSave();
2✔
96
    setIsEditing(false);
2✔
97
  };
2✔
98

2✔
UNCOV
99
  const onCopyClick = () => copy(fileContent);
2✔
100

2✔
101
  const onDrop = acceptedFiles => {
14✔
102
    const reader = new FileReader();
3✔
103
    reader.fileName = acceptedFiles[0].name;
3✔
104
    reader.onerror = error => {
3✔
105
      console.log('Error: ', error);
2✔
106
      setIsEditing(false);
2✔
107
    };
2✔
108
    reader.onload = () => {
3✔
109
      setFileContent(reader.result);
3✔
110
      setIsEditing(true);
3✔
111
    };
2✔
112
    reader.readAsBinaryString(acceptedFiles[0]);
3✔
113
  };
2✔
114

2✔
115
  const handleEditorDidMount = (editor, monaco) => {
14✔
116
    monaco.languages.html.registerHTMLLanguageService(ssoItem.metadataFormat, {}, { documentFormattingEdits: true });
2✔
117
    editorRef.current = { editor, monaco, modifiedEditor: editor };
2✔
118
  };
2✔
119

2✔
120
  return (
14✔
121
    <Drawer className={`${open ? 'fadeIn' : 'fadeOut'}`} anchor="right" open={open} onClose={onClose} PaperProps={{ style: { minWidth: '75vw' } }}>
2✔
122
      <DrawerTitle
2✔
123
        title={`${ssoItem.title} metadata`}
2✔
124
        preCloser={
2✔
125
          <Dropzone multiple={false} onDrop={onDrop}>
2✔
126
            {({ getRootProps, getInputProps }) => (
2✔
127
              <div {...getRootProps()}>
11✔
128
                <input {...getInputProps()} />
2✔
129
                <Button startIcon={<CloudUpload fontSize="small" />}>Import from a file</Button>
2✔
130
              </div>
2✔
131
            )}
2✔
132
          </Dropzone>
2✔
133
        }
2✔
134
        onClose={onClose}
2✔
135
      />
2✔
136
      <Divider light />
2✔
137
      <Editor
2✔
138
        {...editorProps}
2✔
139
        language={ssoItem.editorLanguage}
2✔
140
        defaultLanguage={ssoItem.editorLanguage}
2✔
141
        options={{
2✔
142
          ...editorProps.options,
2✔
143
          readOnly: hasSSOConfig && !isEditing
2✔
144
        }}
2✔
145
        className="editor modified"
2✔
146
        onChange={setFileContent}
2✔
147
        onMount={handleEditorDidMount}
2✔
148
        value={fileContent}
2✔
149
      />
2✔
150
      {!isMetadataValid && fileContent.length > 4 && <div className="error">There was an error parsing the metadata.</div>}
2✔
151
      <Divider className="margin-top-large margin-bottom" light />
2✔
152
      <div>
2✔
153
        {hasSSOConfig && !isEditing ? (
2✔
154
          <div className="flexbox center-aligned">
2✔
155
            <Button onClick={onEditClick}>Edit</Button>
2✔
156
            <Button onClick={onDownloadClick}>Download file</Button>
2✔
157
            <Button onClick={onCopyClick} startIcon={<CopyPasteIcon />}>
2✔
158
              Copy to clipboard
2✔
159
            </Button>
2✔
160
          </div>
2✔
161
        ) : (
2✔
162
          <>
2✔
163
            <Button onClick={onCancelClick}>Cancel</Button>
2✔
164
            <Button variant="contained" disabled={!isMetadataValid} onClick={onSubmitClick} style={{ marginLeft: 10 }}>
2✔
165
              Save
2✔
166
            </Button>
2✔
167
          </>
2✔
168
        )}
2✔
169
      </div>
2✔
170
    </Drawer>
2✔
171
  );
2✔
172
};
2✔
173

2✔
174
export default SSOEditor;
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