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

barseghyanartur / faker-file-ui / 5548062406

13 Jul 2023 09:27PM UTC coverage: 75.587% (-1.1%) from 76.699%
5548062406

push

github-actions

barseghyanartur
Support new providers

51 of 71 branches covered (71.83%)

Branch coverage included in aggregate %.

2 of 2 new or added lines in 1 file covered. (100.0%)

110 of 142 relevant lines covered (77.46%)

1211.37 hits per line

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

74.88
/src/FileGenerator.js
1
import * as React from "react";
2
import { useState, useEffect } from "react";
3
import { createTheme, ThemeProvider } from "@mui/material/styles";
4
import Checkbox from "@mui/material/Checkbox";
5
import FormControlLabel from "@mui/material/FormControlLabel";
6
import {
7
  Grid,
8
  Link,
9
  List,
10
  ListItemButton,
11
  ListItemText,
12
  TextField,
13
  Typography,
14
  Button,
15
} from "@mui/material";
16
import Box from "@mui/material/Box";
17
import Backdrop from "@mui/material/Backdrop";
18
import CircularProgress from "@mui/material/CircularProgress";
19
import Item from "@mui/material/Grid";
20
import Snackbar from "@mui/material/Snackbar";
21
import Alert from "@mui/material/Alert";
22
import axios from "axios";
23
import axiosRetry from "axios-retry";
24

25
function App() {
26
  if (process.env.NODE_ENV === "production") {
1,980!
27
    console.log = function () {};
×
28
    console.debug = function () {};
×
29
    console.info = function () {};
×
30
    console.warn = console.error;
×
31
  }
32

33
  const apiUrl = process.env.REACT_APP_API_URL;
1,980✔
34
  const [loading, setLoading] = useState(true);
1,980✔
35
  const [inProgress, setInProgress] = useState(false);
1,974✔
36
  const [endpoints, setEndpoints] = useState(null);
1,974✔
37
  const [selectedEndpoint, setSelectedEndpoint] = useState(null);
1,974✔
38
  const [selectedModel, setSelectedModel] = useState(null);
1,974✔
39
  const [selectedFileExtension, setSelectedFileExtension] = useState(null);
1,974✔
40
  const [formOptions, setFormOptions] = useState({});
1,974✔
41
  const [downloadUrl, setDownloadUrl] = useState(null);
1,974✔
42
  const [models, setModels] = useState(null);
1,974✔
43
  const [filename, setFilename] = useState(null);
1,974✔
44
  const [showError, setShowError] = useState(false);
1,974✔
45
  const [errorMessage, setErrorMessage] = useState(null);
1,974✔
46
  const multilines = [
1,974✔
47
    "content",
48
    "data_columns",
49
    "options",
50
    "mp3_generator_kwargs",
51
    "pdf_generator_kwargs",
52
  ]; // Multi-line fields
53

54
  axiosRetry(axios, {
1,974✔
55
    retries: 20,
56
    retryDelay: (retryCount) => {
57
      console.log("retryCount");
×
58
      console.log(retryCount);
×
59
      return retryCount * 1000;
×
60
    },
61
  });
62

63
  useEffect(() => {
1,974✔
64
    const fetchEndpoints = async () => {
138✔
65
      const response = await axios.get(`${apiUrl}/openapi.json`, {
138✔
66
        retry: {
67
          retries: 20,
68
        },
69
      });
70
      const schema = response.data;
138✔
71
      const paths = schema.paths;
138✔
72
      const endpoints = Object.keys(paths).reduce((acc, path) => {
138✔
73
        const endpoint = path.split("/")[1];
3,450✔
74
        if (endpoint !== "heartbeat" && endpoint !== "providers") {
3,450✔
75
          acc[endpoint] =
3,174✔
76
            paths[path].post.requestBody.content["application/json"].schema;
77
        }
78
        return acc;
3,450✔
79
      }, {});
80
      setEndpoints(endpoints);
138✔
81
      console.log("ENDPOINTS");
138✔
82
      console.log(endpoints);
138✔
83

84
      const models = schema.components.schemas;
138✔
85
      setModels(models);
138✔
86
      setLoading(false);
138✔
87
      console.log("MODELS");
138✔
88
      console.log(models);
138✔
89
    };
90
    fetchEndpoints();
138✔
91
  }, []);
92

93
  useEffect(() => {
1,974✔
94
    if (endpoints && selectedEndpoint) {
414✔
95
      console.log(endpoints[selectedEndpoint]);
138✔
96
      setFormOptions(
138✔
97
        Object.fromEntries(
98
          Object.entries(endpoints[selectedEndpoint].properties || {}).map(
276✔
99
            ([name, property]) => [name, property.default]
×
100
          )
101
        )
102
      );
103
    }
104
  }, [endpoints, selectedEndpoint]);
105

106
  const handleEndpointClick = (endpoint) => {
1,974✔
107
    console.log(endpoint);
138✔
108
    setSelectedEndpoint(endpoint);
138✔
109
    setSelectedFileExtension(endpoint.slice(0, endpoint.indexOf("_file")));
138✔
110
    setSelectedModel(`${endpoint}_model`);
138✔
111
    console.log(`model: ${endpoint}_model`);
138✔
112
    console.log(models[`${endpoint}_model`]);
138✔
113
    setFormOptions(models[`${endpoint}_model`].properties || {});
138!
114
    setDownloadUrl(null);
138✔
115
    setFilename(null);
138✔
116
  };
117

118
  const handleOptionChange = (event) => {
1,974✔
119
    const { name, value, checked } = event.target;
1,284✔
120
    console.log(models[selectedModel].properties);
1,284✔
121
    console.log(name);
1,284✔
122
    console.log(models[selectedModel].properties[name]);
1,284✔
123
    console.log("checked");
1,284✔
124
    console.log(checked);
1,284✔
125
    setFormOptions((prevOptions) => ({
1,284✔
126
      ...prevOptions,
127
      [name]:
128
        models[selectedModel].properties[name].type === "boolean"
1,284!
129
          ? checked
130
          : value,
131
    }));
132
  };
133

134
  const handleSubmit = async () => {
1,974✔
135
    try {
69✔
136
      setInProgress(true);
69✔
137
      const body = JSON.stringify(
69✔
138
        Object.fromEntries(
139
          Object.entries(formOptions).map(([name, value]) => {
140
            if (["data_columns"].includes(name) && typeof value === "string") {
150✔
141
              if (["csv_file"].includes(selectedModel)) {
3!
142
                value = value.split(",").map((str) => str.trim());
×
143
              } else {
144
                value = JSON.parse(value);
3✔
145
              }
146
            } else if (
147!
147
              [
147!
148
                "options",
149
                "mp3_generator_kwargs",
150
                "pdf_generator_kwargs",
151
              ].includes(name) &&
152
              typeof value === "string" &&
153
              value.trim() !== ""
154
            ) {
155
              try {
×
156
                value = JSON.parse(value);
×
157
              } catch (e) {
158
                console.log("invalid value");
×
159
                console.log(value);
×
160
                value = null;
×
161
              }
162
            } else if (["size"].includes(name) && typeof value === "string" && value.trim() !== "") {
147!
163
              value = value.split(",");
×
164
            }
165
            console.log("name");
150✔
166
            console.log(name);
150✔
167
            console.log("value");
150✔
168
            console.log(value);
150✔
169
            if (value && value.constructor === String && value.trim() === "") {
150!
170
              value = null;
×
171
            }
172
            return [name, value];
150✔
173
          })
174
        )
175
      );
176
      console.log("body");
69✔
177
      console.log(body);
69✔
178
      const response = await fetch(`${apiUrl}/${selectedEndpoint}/`, {
69✔
179
        method: "POST",
180
        headers: {
181
          "Content-Type": "application/json",
182
        },
183
        body: body,
184
      });
185

186
      if (!response.ok) {
69!
187
        const errorResponse = await response.json();
×
188
        console.error("Server responded with an error:", errorResponse);
×
189
        // If errorResponse contains a message, use it. Otherwise use a default message
190
        const _errorMessage = errorResponse.message || "An error occurred";
×
191
        // Handle the error based on errorResponse here
192
        setInProgress(false);
×
193
        setErrorMessage(_errorMessage);
×
194
        setShowError(true);
×
195
        return;
×
196
      }
197

198
      const blob = await response.blob();
69✔
199
      console.log("response");
69✔
200
      console.log(response);
69✔
201
      const downloadUrl = window.URL.createObjectURL(blob);
69✔
202
      setDownloadUrl(downloadUrl);
69✔
203
      setInProgress(false);
69✔
204

205
      // Get the content-disposition header
206
      const contentDisposition = response.headers.get("content-disposition");
69✔
207
      console.log(contentDisposition);
69✔
208

209
      // Extract the 'filename' value
210
      const match = /filename=([^;]+)/.exec(contentDisposition);
69✔
211
      console.log(match);
69✔
212

213
      let filename;
214
      if (match && match.length > 1) {
69!
215
        filename = match[1];
69✔
216
        setFilename(filename);
69✔
217
      } else {
218
        setFilename(`${selectedEndpoint}.${selectedFileExtension}`);
×
219
      }
220
      console.log("filename");
69✔
221
      console.log(filename);
69✔
222
    } catch (err) {
223
      console.log("An error occurred:");
×
224
      console.log(err);
×
225
      console.error("An error occurred:", err);
×
226
      // If err object contains a message, use it. Otherwise use a default message
227
      const _errorMessage = err.message || "An error occurred";
×
228

229
      // Handle the error here
230
      setInProgress(false);
×
231
      setErrorMessage(_errorMessage);
×
232
      setShowError(true);
×
233
    }
234
  };
235

236
  const theme = createTheme();
1,974✔
237

238
  if (loading) {
1,974✔
239
    return (
138✔
240
      <ThemeProvider theme={theme}>
241
        <Box
242
          sx={{
243
            display: "flex",
244
            justifyContent: "center",
245
            alignItems: "center",
246
          }}
247
        >
248
          <CircularProgress size={200} />
249
        </Box>
250
      </ThemeProvider>
251
    );
252
  }
253

254
  return (
1,836✔
255
    <ThemeProvider theme={theme}>
256
      <Grid
257
        container
258
        spacing={0}
259
        columns={12}
260
        sx={{
261
          "--Grid-borderWidth": "1px",
262
          borderTop: "var(--Grid-borderWidth) solid",
263
          borderLeft: "var(--Grid-borderWidth) solid",
264
          borderColor: "divider",
265
          "& > div": {
266
            borderRight: "var(--Grid-borderWidth) solid",
267
            borderBottom: "var(--Grid-borderWidth) solid",
268
            borderColor: "divider",
269
          },
270
        }}
271
      >
272
        <Grid item xs={2}>
273
          <Item sx={{ py: 2, px: 2 }}>
274
            <Typography variant="h4" component="h1" gutterBottom>
275
              File type
276
            </Typography>
277
            <List component="nav" aria-label="main providers folders">
278
              {endpoints &&
3,672✔
279
                Object.keys(endpoints).map((endpoint) => (
280
                  <ListItemButton
42,228✔
281
                    key={endpoint}
282
                    selected={selectedEndpoint === endpoint}
283
                    onClick={() => handleEndpointClick(endpoint)}
138✔
284
                  >
285
                    <ListItemText primary={endpoint.split("_file")[0].replace(/_/g, " ")} />
286
                  </ListItemButton>
287
                ))}
288
            </List>
289
          </Item>
290
        </Grid>
291
        <Grid item xs={8}>
292
          <Item sx={{ py: 2, px: 2 }}>
293
            <Typography variant="h4" component="h1" gutterBottom>
294
              Options
295
            </Typography>
296
            {selectedEndpoint && endpoints && (
5,232✔
297
              <div>
298
                <form>
299
                  {Object.entries(models[selectedModel].properties || {}).map(
1,698!
300
                    ([name, property]) => {
301
                      const inputProps = {
10,068✔
302
                        style: { height: "auto" },
303
                      };
304
                      const props = multilines.includes(name)
10,068✔
305
                        ? { multiline: true, rows: 4, maxRows: 20, inputProps }
306
                        : {};
307
                      const key = `${selectedModel}_${name}`;
10,068✔
308
                      if (property.type === "boolean") {
10,068✔
309
                        return (
36✔
310
                          <FormControlLabel
311
                            key={key}
312
                            control={
313
                              <Checkbox
314
                                name={name}
315
                                label={name}
316
                                checked={
317
                                  formOptions[name] || property.default || false
96✔
318
                                }
319
                                margin="normal"
320
                                variant="outlined"
321
                                onChange={handleOptionChange}
322
                                {...props}
323
                              />
324
                            }
325
                            label={property.title || name}
36!
326
                          />
327
                        );
328
                      } else {
329
                        return (
10,032✔
330
                          <TextField
331
                            key={key}
332
                            name={name}
333
                            label={property.title || name}
10,032!
334
                            defaultValue={property.default || null}
17,469✔
335
                            fullWidth
336
                            margin="normal"
337
                            variant="outlined"
338
                            onChange={handleOptionChange}
339
                            {...props}
340
                          />
341
                        );
342
                      }
343
                    }
344
                  )}
345
                  <Button
346
                    variant="contained"
347
                    color="primary"
348
                    onClick={handleSubmit}
349
                  >
350
                    Generate
351
                  </Button>
352
                  <Snackbar
353
                    anchorOrigin={{ vertical: "bottom", horizontal: "center" }}
354
                    open={showError}
355
                    autoHideDuration={5000}
356
                    onClose={() => setShowError(false)}
×
357
                  >
358
                    <Alert severity="error">{errorMessage}</Alert>
359
                  </Snackbar>
360
                </form>
361

362
                <Backdrop
363
                  sx={{
364
                    color: "#fff",
365
                    zIndex: (theme) => theme.zIndex.drawer + 1,
1,836✔
366
                  }}
367
                  open={inProgress}
368
                >
369
                  <CircularProgress color="inherit" />
370
                </Backdrop>
371
              </div>
372
            )}
373
          </Item>
374
        </Grid>
375
        <Grid item xs={2}>
376
          <Item sx={{ py: 2, px: 2 }}>
377
            <Typography variant="h4" component="h1" gutterBottom>
378
              Result
379
            </Typography>
380
            {downloadUrl && (
1,905✔
381
              <Link href={downloadUrl} download={`${filename}`}>
382
                Download
383
              </Link>
384
            )}
385
          </Item>
386
        </Grid>
387
      </Grid>
388
    </ThemeProvider>
389
  );
390
}
391

392
export default App;
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

© 2026 Coveralls, Inc