From 57c0b7cca104beec051c9a411113929382cb0eda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20F=C3=A9lix?= Date: Thu, 7 Nov 2019 12:59:37 +0000 Subject: [PATCH] feat: add date range download dialog --- new-lamassu-admin/package-lock.json | 66 +++----- new-lamassu-admin/package.json | 1 + new-lamassu-admin/src/components/Popover.js | 44 +++++ .../components/date-range-picker/Calendar.js | 144 +++++++++++++++++ .../date-range-picker/DateRangePicker.js | 131 +++++++++++++++ .../src/components/date-range-picker/Tile.js | 94 +++++++++++ .../src/components/inputs/base/RadioGroup.js | 32 ++++ .../src/components/inputs/index.js | 3 +- .../src/components/typography/styles.js | 5 + new-lamassu-admin/src/pages/ServerLogs.js | 150 +++++++++++++++--- .../src/styling/icons/arrow/download_logs.svg | 14 ++ .../src/styling/icons/arrow/month_change.svg | 20 +++ .../src/styling/icons/month arrows/left.svg | 27 ++++ .../src/styling/icons/month arrows/right.svg | 27 ++++ 14 files changed, 696 insertions(+), 62 deletions(-) create mode 100644 new-lamassu-admin/src/components/Popover.js create mode 100644 new-lamassu-admin/src/components/date-range-picker/Calendar.js create mode 100644 new-lamassu-admin/src/components/date-range-picker/DateRangePicker.js create mode 100644 new-lamassu-admin/src/components/date-range-picker/Tile.js create mode 100644 new-lamassu-admin/src/components/inputs/base/RadioGroup.js create mode 100644 new-lamassu-admin/src/styling/icons/arrow/download_logs.svg create mode 100644 new-lamassu-admin/src/styling/icons/arrow/month_change.svg create mode 100644 new-lamassu-admin/src/styling/icons/month arrows/left.svg create mode 100644 new-lamassu-admin/src/styling/icons/month arrows/right.svg diff --git a/new-lamassu-admin/package-lock.json b/new-lamassu-admin/package-lock.json index bdc74ca3..1c9e6540 100644 --- a/new-lamassu-admin/package-lock.json +++ b/new-lamassu-admin/package-lock.json @@ -6508,8 +6508,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -6530,14 +6529,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6552,20 +6549,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -6682,8 +6676,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -6695,7 +6688,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -6710,7 +6702,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -6718,14 +6709,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -6744,7 +6733,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -6825,8 +6813,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -6838,7 +6825,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -6924,8 +6910,7 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -6961,7 +6946,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -6981,7 +6965,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -7025,14 +7008,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, @@ -8064,7 +8045,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dev": true, "requires": { "es5-ext": "^0.10.50", "type": "^1.0.1" @@ -8880,7 +8860,6 @@ "version": "0.10.51", "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.51.tgz", "integrity": "sha512-oRpWzM2WcLHVKpnrcyB7OW8j/s67Ba04JCm0WnNv3RiABSvs7mrQlutB8DBv793gKcp0XENR8Il8WxGTlZ73gQ==", - "dev": true, "requires": { "es6-iterator": "~2.0.3", "es6-symbol": "~3.1.1", @@ -8897,7 +8876,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "dev": true, "requires": { "d": "1", "es5-ext": "^0.10.35", @@ -8914,7 +8892,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.2.tgz", "integrity": "sha512-/ZypxQsArlv+KHpGvng52/Iz8by3EQPxhmbuz8yFG89N/caTFBSbcXONDw0aMjy827gQg26XAjP4uXFvnfINmQ==", - "dev": true, "requires": { "d": "^1.0.1", "es5-ext": "^0.10.51" @@ -12702,14 +12679,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -12729,8 +12704,7 @@ "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", @@ -14733,6 +14707,14 @@ "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" }, + "moment-range": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/moment-range/-/moment-range-4.0.2.tgz", + "integrity": "sha512-n8sceWwSTjmz++nFHzeNEUsYtDqjgXgcOBzsHi+BoXQU2FW+eU92LUaK8gqOiSu5PG57Q9sYj1Fz4LRDj4FtKA==", + "requires": { + "es6-symbol": "^3.1.0" + } + }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -14842,8 +14824,7 @@ "next-tick": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", - "dev": true + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" }, "nice-try": { "version": "1.0.5", @@ -21979,8 +21960,7 @@ "type": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", - "dev": true + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" }, "type-check": { "version": "0.3.2", diff --git a/new-lamassu-admin/package.json b/new-lamassu-admin/package.json index 813a6ba2..a44911c9 100644 --- a/new-lamassu-admin/package.json +++ b/new-lamassu-admin/package.json @@ -15,6 +15,7 @@ "jss-plugin-extend": "^10.0.0", "lodash": "4.17.15", "moment": "2.24.0", + "moment-range": "^4.0.2", "qrcode.react": "0.9.3", "react": "^16.10.2", "react-dom": "^16.10.2", diff --git a/new-lamassu-admin/src/components/Popover.js b/new-lamassu-admin/src/components/Popover.js new file mode 100644 index 00000000..1fd851a3 --- /dev/null +++ b/new-lamassu-admin/src/components/Popover.js @@ -0,0 +1,44 @@ +import React from 'react' +import { makeStyles, Popover as MaterialPopover } from '@material-ui/core' + +const styles = { + arrow: { + width: 0, + height: 0, + position: 'absolute', + borderStyle: 'solid', + margin: 5, + borderWidth: [[0, 15, 18, 15]], + borderLeftColor: 'transparent', + borderRightColor: 'transparent', + borderTopColor: 'transparent', + top: -18, + left: 138, + marginTop: 0, + marginBottom: 0, + borderColor: '#ffffff' + }, + paper: { + overflow: 'visible' + } +} + +const useStyles = makeStyles(styles) + +const Popover = ({ children, ...props }) => { + const classes = useStyles() + + return ( + + {children} +
+ + ) +} + +export default Popover diff --git a/new-lamassu-admin/src/components/date-range-picker/Calendar.js b/new-lamassu-admin/src/components/date-range-picker/Calendar.js new file mode 100644 index 00000000..a71355d8 --- /dev/null +++ b/new-lamassu-admin/src/components/date-range-picker/Calendar.js @@ -0,0 +1,144 @@ +import React, { useState } from 'react' +import moment from 'moment' +import { toInteger } from 'lodash/fp' +import { makeStyles } from '@material-ui/core/styles' +import Tile from './Tile' +import { ReactComponent as Arrow } from '../../styling/icons/arrow/month_change.svg' +import { primaryColor, zircon, fontSecondary } from '../../styling/variables' +import typographyStyles from '../typography/styles' +const { label2 } = typographyStyles + +const styles = { + navbar: { + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + padding: [[15, 15]], + color: primaryColor, + '& button': { + display: 'flex', + alignItems: 'center', + padding: 0, + border: 'none', + backgroundColor: zircon, + cursor: 'pointer', + borderRadius: '50%', + width: 20, + height: 20, + position: 'relative', + overflow: 'hidden', + '& svg': { + position: 'absolute', + left: 0 + } + }, + fontFamily: fontSecondary, + fontSize: 16, + fontWeight: 500 + }, + table: { + borderCollapse: 'collapse', + color: primaryColor, + '& tr': { + '&:first-child': { + paddingLeft: 5 + }, + '&:last-child': { + paddingRight: 5 + } + }, + '& th, & td': { + margin: 0, + padding: [[3, 0, 3, 0]] + }, + '& th': { + extend: label2 + } + } +} + +const useStyles = makeStyles(styles) + +const Calendar = ({ minDate, maxDate, handleSelect, ...props }) => { + const [currentDisplayedMonth, setCurrentDisplayedMonth] = useState(moment()) + + const classes = useStyles() + + const weekdays = moment.weekdaysMin().map(day => day.slice(0, 1)) + const firstDayOfMonth = (month) => toInteger(moment(month).startOf('month').format('d')) + const monthLength = (month) => toInteger(moment(month).endOf('month').format('D')) + + const monthdays = (month) => { + const days = [] + + const lastMonth = moment(month).subtract(1, 'month') + for (let i = firstDayOfMonth(month) - 1; i >= 0; i--) { + days.push(moment(lastMonth).endOf('month').subtract(i, 'days')) + } + for (let j = 0; j < monthLength(month); j++) { + days.push(moment(month).startOf('month').add(j, 'days')) + } + const nextMonth = moment(month).add(1, 'month') + for (let k = 0; days.length < 42; k++) { + days.push(moment(nextMonth).startOf('month').add(k, 'days')) + } + + return days + } + + const getRow = (month, row) => monthdays(month).slice(row * 7 - 7, row * 7) + + const handleNavPrev = (currentMonth) => { + const prevMonth = moment(currentMonth).subtract(1, 'month') + if (!minDate) setCurrentDisplayedMonth(prevMonth) + else setCurrentDisplayedMonth(prevMonth.isSameOrAfter(minDate, 'month') ? prevMonth : currentDisplayedMonth) + } + const handleNavNext = (currentMonth) => { + const nextMonth = moment(currentMonth).add(1, 'month') + if (!maxDate) setCurrentDisplayedMonth(nextMonth) + else setCurrentDisplayedMonth(nextMonth.isSameOrBefore(maxDate, 'month') ? nextMonth : currentDisplayedMonth) + } + + return ( +
+
+ + {`${currentDisplayedMonth.format('MMMM')} ${currentDisplayedMonth.format('YYYY')}`} + +
+ + + + {weekdays.map((day, key) => ( + + ))} + + + + {[1, 2, 3, 4, 5, 6, 7].map((row, key) => ( + + {getRow(currentDisplayedMonth, row).map((day, key) => ( + + ))} + + ))} + +
{day}
handleSelect(day, minDate, maxDate)}> + + {day.format('D')} + +
+
+ ) +} + +export default Calendar diff --git a/new-lamassu-admin/src/components/date-range-picker/DateRangePicker.js b/new-lamassu-admin/src/components/date-range-picker/DateRangePicker.js new file mode 100644 index 00000000..a7eefda1 --- /dev/null +++ b/new-lamassu-admin/src/components/date-range-picker/DateRangePicker.js @@ -0,0 +1,131 @@ +import React, { useState, useEffect } from 'react' +import classnames from 'classnames' +import { makeStyles } from '@material-ui/core/styles' + +import Calendar from './Calendar' +import { ReactComponent as Arrow } from '../../styling/icons/arrow/download_logs.svg' + +import { primaryColor, offColor, zircon } from '../../styling/variables' + +import typographyStyles from '../typography/styles' +const { info1, label, label3 } = typographyStyles + +const dateContainerStyles = { + wrapper: { + minWidth: 118 + }, + container: { + display: 'flex' + }, + monthWeekDayContainer: { + display: 'flex', + flexDirection: 'column' + }, + label: { + extend: label, + color: primaryColor + }, + bigNumber: { + extend: info1, + marginRight: 7 + }, + monthYear: { + extend: label3, + color: primaryColor + }, + weekDay: { + extend: label, + lineHeight: 1, + color: offColor + } +} + +const dateContainerUseStyles = makeStyles(dateContainerStyles) + +const DateContainer = ({ date, children, ...props }) => { + const classes = dateContainerUseStyles() + + return ( +
+
{children}
+ {date && + <> +
+
{date.format('D')}
+
+ {`${date.format('MMM')} ${date.format('YYYY')}`} + {date.format('dddd')} +
+
+ } +
+ ) +} + +const styles = { + wrapper: { + backgroundColor: 'white', + borderRadius: 10 + }, + dateThingyContainer: { + height: 80, + display: 'flex', + justifyContent: 'space-between', + backgroundColor: zircon, + padding: [[5, 15, 0, 15]] + }, + arrowContainer: { + width: 39, + display: 'flex', + alignSelf: 'center', + alignItems: 'center' + }, + arrow: { + margin: 'auto' + } +} + +const useStyles = makeStyles(styles) + +const DateRangePicker = ({ minDate, maxDate, className, handleChange, ...props }) => { + const [from, setFrom] = useState(null) + const [to, setTo] = useState(null) + + useEffect(() => { + handleChange(from, to) + }, [to]) + + const classes = useStyles() + + const handleSelect = (day, minDate, maxDate) => { + if ((maxDate && day.isAfter(maxDate, 'day')) || (minDate && day.isBefore(minDate, 'day'))) return + if (from && !to) { + if (day.isBefore(from, 'day')) { + setTo(from) + setFrom(day) + } else { + setTo(day) + } + } else { + setFrom(day) + setTo(null) + } + } + + return ( + <> +
+
+ From +
+ +
+ To +
+ +
+ + ) +} + +export default DateRangePicker diff --git a/new-lamassu-admin/src/components/date-range-picker/Tile.js b/new-lamassu-admin/src/components/date-range-picker/Tile.js new file mode 100644 index 00000000..c0132a8b --- /dev/null +++ b/new-lamassu-admin/src/components/date-range-picker/Tile.js @@ -0,0 +1,94 @@ +import React from 'react' +import classnames from 'classnames' +import { makeStyles } from '@material-ui/core/styles' +import { primaryColor, spring2, spring3, fontSecondary, disabledColor } from '../../styling/variables' + +const styles = { + wrapper: { + width: 45, + height: 26, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + position: 'relative' + }, + button: { + border: 'none', + width: '100%', + height: '100%', + cursor: 'pointer', + padding: 0, + backgroundColor: 'transparent', + color: primaryColor, + zIndex: 2, + fontFamily: fontSecondary, + fontSize: 14, + fontWeight: 500 + }, + lowerBound: { + width: [['50%', '!important']], + left: '50%' + }, + upperBound: { + width: [['50%', '!important']], + right: '50%' + }, + selected: { + width: 26, + height: 26, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + backgroundColor: spring2, + borderRadius: '50%', + position: 'absolute', + zIndex: 1 + }, + between: { + position: 'absolute', + width: '100%', + height: '100%', + zIndex: 0, + backgroundColor: spring3 + }, + disabled: { + color: disabledColor, + cursor: 'default' + } +} + +const useStyles = makeStyles(styles) + +const Tile = ({ isLowerBound, isUpperBound, isBetween, isDisabled, children, ...props }) => { + const classes = useStyles() + const selected = isLowerBound || isUpperBound + + const rangeClasses = { + [classes.between]: isBetween && !(isLowerBound && isUpperBound), + [classes.lowerBound]: isLowerBound && !isUpperBound, + [classes.upperBound]: isUpperBound && !isLowerBound + } + + const buttonWrapperClasses = { + [classes.wrapper]: true, + [classes.selected]: selected + } + + const buttonClasses = { + [classes.button]: true, + [classes.disabled]: isDisabled + } + + return ( +
+
+
+ +
+
+ ) +} + +export default Tile diff --git a/new-lamassu-admin/src/components/inputs/base/RadioGroup.js b/new-lamassu-admin/src/components/inputs/base/RadioGroup.js new file mode 100644 index 00000000..cbec62a3 --- /dev/null +++ b/new-lamassu-admin/src/components/inputs/base/RadioGroup.js @@ -0,0 +1,32 @@ +import React from 'react' +import classnames from 'classnames' +import { withStyles } from '@material-ui/styles' +import FormControlLabel from '@material-ui/core/FormControlLabel' +import { Radio as MaterialRadio, RadioGroup as MaterialRadioGroup } from '@material-ui/core' +import { secondaryColor } from '../../../styling/variables' + +const GreenRadio = withStyles({ + root: { + color: secondaryColor, + '&$checked': { + color: secondaryColor + } + }, + checked: {} +})(props => ) + +const RadioGroup = ({ name, value, labels, ariaLabel, onChange, className, ...props }) => { + return ( + <> + {labels && ( + + {labels.map((label, idx) => ( + } label={label} /> + ))} + + )} + + ) +} + +export default RadioGroup diff --git a/new-lamassu-admin/src/components/inputs/index.js b/new-lamassu-admin/src/components/inputs/index.js index c7af2a30..28347d38 100644 --- a/new-lamassu-admin/src/components/inputs/index.js +++ b/new-lamassu-admin/src/components/inputs/index.js @@ -5,5 +5,6 @@ import Radio from './base/Radio' import TextInput from './base/TextInput' import Switch from './base/Switch' import Select from './base/Select' +import RadioGroup from './base/RadioGroup' -export { Autocomplete, AutocompleteMultiple, TextInput, Radio, Checkbox, Switch, Select } +export { Autocomplete, AutocompleteMultiple, TextInput, Radio, Checkbox, Switch, Select, RadioGroup } diff --git a/new-lamassu-admin/src/components/typography/styles.js b/new-lamassu-admin/src/components/typography/styles.js index 06a1eabe..2921b161 100644 --- a/new-lamassu-admin/src/components/typography/styles.js +++ b/new-lamassu-admin/src/components/typography/styles.js @@ -119,6 +119,11 @@ export default { fontWeight: 500, color: fontColor }, + label3: { + fontSize: fontSize5, + fontFamily: fontSecondary, + fontWeight: 700 + }, select: { fontSize: fontSize3, fontFamily: fontSecondary, diff --git a/new-lamassu-admin/src/pages/ServerLogs.js b/new-lamassu-admin/src/pages/ServerLogs.js index 968c275c..6f06d9ae 100644 --- a/new-lamassu-admin/src/pages/ServerLogs.js +++ b/new-lamassu-admin/src/pages/ServerLogs.js @@ -1,26 +1,28 @@ import React, { useState } from 'react' import FileSaver from 'file-saver' -import { concat, uniq } from 'lodash/fp' +import classnames from 'classnames' +import { concat, uniq, toInteger } from 'lodash/fp' import moment from 'moment' import useAxios from '@use-hooks/axios' +import { makeStyles } from '@material-ui/core' import Title from '../components/Title' import { Info3 } from '../components/typography' -import { FeatureButton, SimpleButton } from '../components/buttons' +import { FeatureButton, SimpleButton, Link } from '../components/buttons' import { Table, TableHead, TableRow, TableHeader, TableBody, TableCell } from '../components/table' -import { Select } from '../components/inputs' +import { Select, RadioGroup } from '../components/inputs' import Uptime from '../components/Uptime' +import DateRangePicker from '../components/date-range-picker/DateRangePicker' +import Popover from '../components/Popover' import { ReactComponent as Download } from '../styling/icons/button/download/zodiac.svg' import { ReactComponent as DownloadActive } from '../styling/icons/button/download/white.svg' -import { makeStyles } from '@material-ui/core' -import typographyStyles from '../components/typography/styles' - -import { comet } from '../styling/variables' +import { primaryColor, comet } from '../styling/variables' import styles from './Logs.styles' import logPageHeaderStyles from './LogPageHeader.styles' -const { regularLabel } = typographyStyles +import typographyStyles from '../components/typography/styles' +const { regularLabel, h4 } = typographyStyles const { tableWrapper } = styles const { titleAndButtonsContainer, buttonsWrapper } = logPageHeaderStyles @@ -55,6 +57,40 @@ styles.uptimeContainer = { styles.titleAndButtonsContainer = titleAndButtonsContainer styles.buttonsWrapper = buttonsWrapper +styles.popoverContent = { + minWidth: 315 +} + +styles.popoverHeader = { + extend: h4, + padding: [[20, 15, 0, 15]] +} + +styles.radioButtonsContainer = { + padding: [[10, 15, 10, 15]] +} + +styles.radioButtons = { + display: 'flex', + justifyContent: 'space-between', + flexDirection: 'row', + color: primaryColor +} + +styles.dateRangePickerShowing = { + display: 'block', + height: '100%' +} + +styles.dateRangePickerHidden = { + display: 'none', + height: 0 +} + +styles.download = { + padding: [[30, 15, 30, 15]] +} + const useStyles = makeStyles(styles) const SHOW_ALL = 'Show all' @@ -68,6 +104,9 @@ const Logs = () => { const [logLevel, setLogLevel] = useState(SHOW_ALL) const [version, setVersion] = useState(null) const [processStates, setProcessStates] = useState(null) + const [radioButtons, setRadioButtons] = useState(0) + const [range, setRange] = useState(null) + const [anchorEl, setAnchorEl] = useState(null) const classes = useStyles() @@ -116,12 +155,34 @@ const Logs = () => { } }) - const handleLogLevelChange = (item) => setLogLevel(item) - const formatDateFile = date => { return moment(date).format('YYYY-MM-DD_HH-mm') } + const dateRangePickerClasses = { + [classes.dateRangePickerShowing]: radioButtons === 1, + [classes.dateRangePickerHidden]: radioButtons === 0 + } + + const handleOpenRangePicker = (event) => { + setAnchorEl(event.currentTarget) + } + + const handleCloseRangePicker = () => { + setAnchorEl(null) + } + + const handleRadioButtons = (event) => { + setRadioButtons(toInteger(event.target.value)) + } + + const handleRangeChange = (from, to) => { + setRange({ from, to }) + } + + const open = Boolean(anchorEl) + const id = open ? 'date-range-popover' : undefined + return ( <>
@@ -132,14 +193,67 @@ const Logs = () => { { - const text = logsResponse.data.logs.map(it => JSON.stringify(it)).join('\n') - const blob = new window.Blob([text], { - type: 'text/plain;charset=utf-8' - }) - FileSaver.saveAs(blob, `${formatDateFile(new Date())}_server`) - }} + aria-describedby={id} + variant='contained' + onClick={handleOpenRangePicker} /> + +
+
+ Download logs +
+
+ +
+ +
+ { + if (radioButtons === 0) { + const text = logsResponse.data.logs.map(it => JSON.stringify(it)).join('\n') + const blob = new window.Blob([text], { + type: 'text/plain;charset=utf-8' + }) + FileSaver.saveAs(blob, `${formatDateFile(new Date())}_server`) + } else if (radioButtons === 1 && range.from && range.to) { + const text = logsResponse.data.logs.filter((log) => moment(log.timestamp).isBetween(range.from, range.to, 'day', '[]')).map(it => JSON.stringify(it)).join('\n') + const blob = new window.Blob([text], { + type: 'text/plain;charset=utf-8' + }) + FileSaver.saveAs(blob, `${formatDateFile(range.from)}_${formatDateFile(range.to)}_server`) + } + }} + > + Download + +
+
+
Share with Lamassu @@ -156,7 +270,7 @@ const Logs = () => {
{logsResponse && (