1import { css } from '@emotion/css';
2import { formattedValueToString, getValueFormat, GrafanaTheme2 } from '@grafana/data';
3import React from 'react';
4import { useStyles2 } from '../../themes';
5import { trimFileName } from '../../utils/file';
6import { Button } from '../Button';
7import { Icon } from '../Icon/Icon';
8import { IconButton } from '../IconButton/IconButton';
9import { DropzoneFile } from './FileDropzone';
10
11export const REMOVE_FILE = 'Remove file';
12export interface FileListItemProps {
13  file: DropzoneFile;
14  removeFile?: (file: DropzoneFile) => void;
15}
16
17export function FileListItem({ file: customFile, removeFile }: FileListItemProps) {
18  const styles = useStyles2(getStyles);
19  const { file, progress, error, abortUpload, retryUpload } = customFile;
20
21  const renderRightSide = () => {
22    if (error) {
23      return (
24        <>
25          <span className={styles.error}>{error.message}</span>
26          {retryUpload && (
27            <IconButton
28              type="button"
29              aria-label="Retry"
30              name="sync"
31              tooltip="Retry"
32              tooltipPlacement="top"
33              onClick={retryUpload}
34            />
35          )}
36          {removeFile && (
37            <IconButton
38              className={retryUpload ? styles.marginLeft : ''}
39              type="button"
40              name="trash-alt"
41              onClick={() => removeFile(customFile)}
42              tooltip={REMOVE_FILE}
43              aria-label={REMOVE_FILE}
44            />
45          )}
46        </>
47      );
48    }
49
50    if (progress && file.size > progress) {
51      return (
52        <>
53          <progress className={styles.progressBar} max={file.size} value={progress} />
54          <span className={styles.paddingLeft}>{Math.round((progress / file.size) * 100)}%</span>
55          {abortUpload && (
56            <Button variant="secondary" type="button" fill="text" onClick={abortUpload}>
57              Cancel upload
58            </Button>
59          )}
60        </>
61      );
62    }
63    return (
64      removeFile && (
65        <IconButton
66          name="trash-alt"
67          onClick={() => removeFile(customFile)}
68          tooltip={REMOVE_FILE}
69          aria-label={REMOVE_FILE}
70          type="button"
71          tooltipPlacement="top"
72        />
73      )
74    );
75  };
76
77  const valueFormat = getValueFormat('decbytes')(file.size);
78
79  return (
80    <div className={styles.fileListContainer}>
81      <span className={styles.fileNameWrapper}>
82        <Icon name="file-blank" size="lg" aria-hidden={true} />
83        <span className={styles.padding}>{trimFileName(file.name)}</span>
84        <span>{formattedValueToString(valueFormat)}</span>
85      </span>
86
87      <div className={styles.fileNameWrapper}>{renderRightSide()}</div>
88    </div>
89  );
90}
91
92function getStyles(theme: GrafanaTheme2) {
93  return {
94    fileListContainer: css`
95      width: 100%;
96      display: flex;
97      flex-direction: row;
98      align-items: center;
99      justify-content: space-between;
100      padding: ${theme.spacing(2)};
101      border: 1px dashed ${theme.colors.border.medium};
102      background-color: ${theme.colors.background.secondary};
103      margin-top: ${theme.spacing(1)};
104    `,
105    fileNameWrapper: css`
106      display: flex;
107      flex-direction: row;
108      align-items: center;
109    `,
110    padding: css`
111      padding: ${theme.spacing(0, 1)};
112    `,
113    paddingLeft: css`
114      padding-left: ${theme.spacing(2)};
115    `,
116    marginLeft: css`
117      margin-left: ${theme.spacing(1)};
118    `,
119    error: css`
120      padding-right: ${theme.spacing(2)};
121      color: ${theme.colors.error.text};
122    `,
123    progressBar: css`
124      border-radius: ${theme.spacing(1)};
125      height: 4px;
126      ::-webkit-progress-bar {
127        background-color: ${theme.colors.border.weak};
128        border-radius: ${theme.spacing(1)};
129      }
130      ::-webkit-progress-value {
131        background-color: ${theme.colors.primary.main};
132        border-radius: ${theme.spacing(1)};
133      }
134    `,
135  };
136}
137