dinocollab-core 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/README.md +54 -0
  2. package/dist/_virtual/_rollupPluginBabelHelpers.js +431 -0
  3. package/dist/_virtual/_rollupPluginBabelHelpers.js.map +1 -0
  4. package/dist/assets/vector-404265a04f4f9c8be1f.webp +0 -0
  5. package/dist/node_modules/.pnpm/@rollup_plugin-typescript@1_d0d2002d9033600b6738d939bd598bc6/node_modules/tslib/tslib.es6.js +46 -0
  6. package/dist/node_modules/.pnpm/@rollup_plugin-typescript@1_d0d2002d9033600b6738d939bd598bc6/node_modules/tslib/tslib.es6.js.map +1 -0
  7. package/dist/src/api-context/alert-global.js +151 -0
  8. package/dist/src/api-context/alert-global.js.map +1 -0
  9. package/dist/src/api-context/drawer-global.js +105 -0
  10. package/dist/src/api-context/drawer-global.js.map +1 -0
  11. package/dist/src/api-context/global-modal.js +87 -0
  12. package/dist/src/api-context/global-modal.js.map +1 -0
  13. package/dist/src/api-context/popover-global.js +102 -0
  14. package/dist/src/api-context/popover-global.js.map +1 -0
  15. package/dist/src/api-context/popover.js +86 -0
  16. package/dist/src/api-context/popover.js.map +1 -0
  17. package/dist/src/api-context/ui.units.js +21 -0
  18. package/dist/src/api-context/ui.units.js.map +1 -0
  19. package/dist/src/components/copy-to-clipboard.js +105 -0
  20. package/dist/src/components/copy-to-clipboard.js.map +1 -0
  21. package/dist/src/components/custom.breadcrumbs.js +61 -0
  22. package/dist/src/components/custom.breadcrumbs.js.map +1 -0
  23. package/dist/src/components/help-tooltip.js +91 -0
  24. package/dist/src/components/help-tooltip.js.map +1 -0
  25. package/dist/src/components/image-with-fallback.js +48 -0
  26. package/dist/src/components/image-with-fallback.js.map +1 -0
  27. package/dist/src/components/text-editor.js +117 -0
  28. package/dist/src/components/text-editor.js.map +1 -0
  29. package/dist/src/form/create.autocomplete.chips.js +218 -0
  30. package/dist/src/form/create.autocomplete.chips.js.map +1 -0
  31. package/dist/src/form/create.date-expired.js +201 -0
  32. package/dist/src/form/create.date-expired.js.map +1 -0
  33. package/dist/src/form/create.date-picker.js +125 -0
  34. package/dist/src/form/create.date-picker.js.map +1 -0
  35. package/dist/src/form/create.form-base.js +135 -0
  36. package/dist/src/form/create.form-base.js.map +1 -0
  37. package/dist/src/form/create.form-comfirm.js +119 -0
  38. package/dist/src/form/create.form-comfirm.js.map +1 -0
  39. package/dist/src/form/create.form-grid-layout.js +177 -0
  40. package/dist/src/form/create.form-grid-layout.js.map +1 -0
  41. package/dist/src/form/create.form-grid-layout.units.js +39 -0
  42. package/dist/src/form/create.form-grid-layout.units.js.map +1 -0
  43. package/dist/src/form/create.input-base.js +260 -0
  44. package/dist/src/form/create.input-base.js.map +1 -0
  45. package/dist/src/form/create.input.file.js +74 -0
  46. package/dist/src/form/create.input.file.js.map +1 -0
  47. package/dist/src/form/create.select-simple.js +104 -0
  48. package/dist/src/form/create.select-simple.js.map +1 -0
  49. package/dist/src/form/create.select-with-api.js +271 -0
  50. package/dist/src/form/create.select-with-api.js.map +1 -0
  51. package/dist/src/form/create.text-editor.js +156 -0
  52. package/dist/src/form/create.text-editor.js.map +1 -0
  53. package/dist/src/form/dino-form.js +42 -0
  54. package/dist/src/form/dino-form.js.map +1 -0
  55. package/dist/src/form/helper.js +157 -0
  56. package/dist/src/form/helper.js.map +1 -0
  57. package/dist/src/form/modal-wrapper.js +75 -0
  58. package/dist/src/form/modal-wrapper.js.map +1 -0
  59. package/dist/src/form/validator.js +186 -0
  60. package/dist/src/form/validator.js.map +1 -0
  61. package/dist/src/hooks/index.js +48 -0
  62. package/dist/src/hooks/index.js.map +1 -0
  63. package/dist/src/index.js +26 -0
  64. package/dist/src/index.js.map +1 -0
  65. package/dist/src/redux/create.hoc-lazy.js +67 -0
  66. package/dist/src/redux/create.hoc-lazy.js.map +1 -0
  67. package/dist/src/redux/dino.js +11 -0
  68. package/dist/src/redux/dino.js.map +1 -0
  69. package/dist/src/redux/types.js +9 -0
  70. package/dist/src/redux/types.js.map +1 -0
  71. package/dist/src/redux/ui.error-page.js +80 -0
  72. package/dist/src/redux/ui.error-page.js.map +1 -0
  73. package/dist/src/redux/vector-404.webp.js +4 -0
  74. package/dist/src/redux/vector-404.webp.js.map +1 -0
  75. package/dist/src/table/context.js +12 -0
  76. package/dist/src/table/context.js.map +1 -0
  77. package/dist/src/table/create.action-row.js +135 -0
  78. package/dist/src/table/create.action-row.js.map +1 -0
  79. package/dist/src/table/create.status-cell.js +49 -0
  80. package/dist/src/table/create.status-cell.js.map +1 -0
  81. package/dist/src/table/create.table.js +233 -0
  82. package/dist/src/table/create.table.js.map +1 -0
  83. package/dist/src/table/custom.filter-operators.js +89 -0
  84. package/dist/src/table/custom.filter-operators.js.map +1 -0
  85. package/dist/src/table/dino.js +129 -0
  86. package/dist/src/table/dino.js.map +1 -0
  87. package/dist/src/table/helpers.js +116 -0
  88. package/dist/src/table/helpers.js.map +1 -0
  89. package/dist/src/table/model-filter.js +23 -0
  90. package/dist/src/table/model-filter.js.map +1 -0
  91. package/dist/src/table/toolbar-pannel.js +134 -0
  92. package/dist/src/table/toolbar-pannel.js.map +1 -0
  93. package/dist/src/table/ui.buttons.js +60 -0
  94. package/dist/src/table/ui.buttons.js.map +1 -0
  95. package/dist/src/table/ui.units.js +201 -0
  96. package/dist/src/table/ui.units.js.map +1 -0
  97. package/dist/src/utils/dayjs-config.js +12 -0
  98. package/dist/src/utils/dayjs-config.js.map +1 -0
  99. package/dist/src/utils/helpers.js +197 -0
  100. package/dist/src/utils/helpers.js.map +1 -0
  101. package/dist/src/utils/json-object.js +38 -0
  102. package/dist/src/utils/json-object.js.map +1 -0
  103. package/dist/src/utils/query-param.js +172 -0
  104. package/dist/src/utils/query-param.js.map +1 -0
  105. package/package.json +52 -0
  106. package/rollup.config.js +39 -0
  107. package/src/@types/global.d.ts +5 -0
  108. package/src/api-context/alert-global.tsx +174 -0
  109. package/src/api-context/drawer-global.tsx +116 -0
  110. package/src/api-context/global-modal.tsx +109 -0
  111. package/src/api-context/index.ts +13 -0
  112. package/src/api-context/popover-global.tsx +107 -0
  113. package/src/api-context/popover.tsx +89 -0
  114. package/src/api-context/ui.units.tsx +10 -0
  115. package/src/components/copy-to-clipboard.tsx +86 -0
  116. package/src/components/custom.breadcrumbs.tsx +67 -0
  117. package/src/components/help-tooltip.tsx +75 -0
  118. package/src/components/image-with-fallback.tsx +51 -0
  119. package/src/components/index.tsx +1 -0
  120. package/src/components/input-debounce-timer.tsx +138 -0
  121. package/src/components/loading-buttons.tsx +35 -0
  122. package/src/components/text-editor.preview.tsx +30 -0
  123. package/src/components/text-editor.tsx +125 -0
  124. package/src/form/README.md +55 -0
  125. package/src/form/create.autocomplete.chips.tsx +199 -0
  126. package/src/form/create.date-expired.tsx +195 -0
  127. package/src/form/create.date-picker.tsx +122 -0
  128. package/src/form/create.form-base.tsx +102 -0
  129. package/src/form/create.form-comfirm.tsx +83 -0
  130. package/src/form/create.form-grid-layout.tsx +170 -0
  131. package/src/form/create.form-grid-layout.units.tsx +37 -0
  132. package/src/form/create.input-base.tsx +222 -0
  133. package/src/form/create.input.file.tsx +76 -0
  134. package/src/form/create.select-simple.tsx +101 -0
  135. package/src/form/create.select-with-api.tsx +213 -0
  136. package/src/form/create.text-editor.tsx +161 -0
  137. package/src/form/dino-form.tsx +40 -0
  138. package/src/form/helper.ts +132 -0
  139. package/src/form/index.ts +12 -0
  140. package/src/form/modal-wrapper.tsx +75 -0
  141. package/src/form/types.ts +16 -0
  142. package/src/form/validator.ts +202 -0
  143. package/src/hooks/index.ts +44 -0
  144. package/src/index.ts +7 -0
  145. package/src/lab/create.autocomplete.simple.tsx +57 -0
  146. package/src/lab/create.dino-store.ts +59 -0
  147. package/src/lab/create.multi-select-dropdown.tsx +189 -0
  148. package/src/lab/create.select-mul-with-api/index.tsx +271 -0
  149. package/src/lab/create.select-mul-with-api/table-custom.tsx +194 -0
  150. package/src/lab/create.select-mul-with-api/types.ts +26 -0
  151. package/src/lab/create.select-mul-with-api/ui.units.tsx +163 -0
  152. package/src/lab/filter-bar/base.tsx +162 -0
  153. package/src/lab/filter-bar/create.filter-bar.tsx +190 -0
  154. package/src/lab/filter-bar/create.filter-menu.tsx +156 -0
  155. package/src/lab/filter-bar/create.filter-panel.tsx +95 -0
  156. package/src/lab/filter-bar/create.filtered.tsx +41 -0
  157. package/src/lab/filter-bar/create.sort-menu.tsx +43 -0
  158. package/src/lab/filter-bar/demo.tsx +50 -0
  159. package/src/lab/filter-bar/index.ts +6 -0
  160. package/src/lab/filter-bar/types.ts +105 -0
  161. package/src/lab/filter-bar/ui.units.tsx +70 -0
  162. package/src/lab/grafana-dashboard/configs.ts +43 -0
  163. package/src/lab/grafana-dashboard/date-time-range/absolute-time-rage.tsx +137 -0
  164. package/src/lab/grafana-dashboard/date-time-range/helpers.ts +126 -0
  165. package/src/lab/grafana-dashboard/date-time-range/index.tsx +62 -0
  166. package/src/lab/grafana-dashboard/date-time-range/menu-wrap.tsx +101 -0
  167. package/src/lab/grafana-dashboard/date-time-range/quick-ranges.tsx +161 -0
  168. package/src/lab/grafana-dashboard/date-time-range/types.ts +9 -0
  169. package/src/lab/grafana-dashboard/date-time-range/units.tsx +18 -0
  170. package/src/lab/grafana-dashboard/helper.ts +25 -0
  171. package/src/lab/grafana-dashboard/hooks.tsx +79 -0
  172. package/src/lab/grafana-dashboard/icons.tsx +67 -0
  173. package/src/lab/grafana-dashboard/index.tsx +120 -0
  174. package/src/lab/grafana-dashboard/top-bar.tsx +62 -0
  175. package/src/lab/grafana-dashboard/top-bar.types.ts +5 -0
  176. package/src/lab/grafana-dashboard/types.ts +8 -0
  177. package/src/lab/media-player.core1.tsx +273 -0
  178. package/src/lab/media-player.muted.tsx +62 -0
  179. package/src/lab/media-player.units.ts +80 -0
  180. package/src/lab/table-grid/create.table-grid.tsx +183 -0
  181. package/src/lab/table-grid/demo.tsx +53 -0
  182. package/src/lab/table-grid/dino.tsx +8 -0
  183. package/src/lab/table-grid/helpers.tsx +11 -0
  184. package/src/lab/table-grid/index.ts +3 -0
  185. package/src/lab/table-grid/item-actions.tsx +138 -0
  186. package/src/lab/table-grid/toolbar-pannel.tsx +98 -0
  187. package/src/lab/table-grid/types.ts +68 -0
  188. package/src/redux/create.hoc-lazy.tsx +80 -0
  189. package/src/redux/dino.ts +9 -0
  190. package/src/redux/index.ts +6 -0
  191. package/src/redux/types.ts +27 -0
  192. package/src/redux/ui.error-page.tsx +62 -0
  193. package/src/redux/ui.units.tsx +41 -0
  194. package/src/redux/vector-404.webp +0 -0
  195. package/src/table/context.tsx +16 -0
  196. package/src/table/create.action-row.tsx +91 -0
  197. package/src/table/create.status-cell.tsx +51 -0
  198. package/src/table/create.table.tsx +239 -0
  199. package/src/table/custom.filter-operators.ts +94 -0
  200. package/src/table/dino.tsx +120 -0
  201. package/src/table/helpers.ts +94 -0
  202. package/src/table/index.ts +13 -0
  203. package/src/table/model-filter.ts +43 -0
  204. package/src/table/toolbar-pannel.tsx +106 -0
  205. package/src/table/types.ts +50 -0
  206. package/src/table/ui.buttons.tsx +54 -0
  207. package/src/table/ui.units.tsx +189 -0
  208. package/src/utils/dayjs-config.ts +13 -0
  209. package/src/utils/helpers.ts +171 -0
  210. package/src/utils/index.ts +7 -0
  211. package/src/utils/json-object.ts +29 -0
  212. package/src/utils/mfe-events.tsx +34 -0
  213. package/src/utils/query-param.ts +129 -0
  214. package/tsconfig.json +20 -0
@@ -0,0 +1,70 @@
1
+ import React, { FC } from 'react'
2
+ import { Box, Fade, IconButton, IconButtonProps, styled, Tooltip, Typography } from '@mui/material'
3
+ import CloseIcon from '@mui/icons-material/Close'
4
+ import HelpTooltip from '../../components/help-tooltip'
5
+
6
+ interface ButtonClearProps {
7
+ visibled?: boolean
8
+ onClick: IconButtonProps['onClick']
9
+ }
10
+
11
+ export const ButtonClear: FC<ButtonClearProps> = (props) => (
12
+ <WrapIcon>
13
+ <Tooltip title='Remove filter'>
14
+ <Fade in={props.visibled} unmountOnExit>
15
+ <IconButton size='small' onClick={props.onClick}>
16
+ <CloseIcon fontSize='small' />
17
+ </IconButton>
18
+ </Fade>
19
+ </Tooltip>
20
+ </WrapIcon>
21
+ )
22
+
23
+ export interface FilterHelpNotesProps {
24
+ title?: string
25
+ items?: string[]
26
+ }
27
+
28
+ export const FilterHelpNotes: FC<FilterHelpNotesProps> = (props) => {
29
+ if (!props.items || props.items.length < 1) return <></>
30
+ return (
31
+ <WrapIcon>
32
+ <HelpTooltip small title={props.title ?? 'The search includes'}>
33
+ <WrapList>
34
+ {props.items.map((item, index) => (
35
+ <Typography key={index} component='li' variant='body2'>
36
+ {item}
37
+ </Typography>
38
+ ))}
39
+ </WrapList>
40
+ </HelpTooltip>
41
+ </WrapIcon>
42
+ )
43
+ }
44
+
45
+ const WrapIcon = styled(Box)({
46
+ display: 'flex',
47
+ flex: '0 0 auto',
48
+ width: '40px',
49
+ height: '40px',
50
+ justifyContent: 'center',
51
+ alignItems: 'center'
52
+ })
53
+
54
+ const WrapList = styled('ul')({
55
+ paddingLeft: '1.7rem',
56
+ marginBottom: 0,
57
+ li: {
58
+ position: 'relative',
59
+ textAlign: 'justify',
60
+ '&::before': {
61
+ content: '"►"',
62
+ display: 'block',
63
+ position: 'absolute',
64
+ top: '50%',
65
+ right: 'calc(100% + 6px)',
66
+ transform: 'translateY(-50%)',
67
+ fontSize: '0.9em'
68
+ }
69
+ }
70
+ })
@@ -0,0 +1,43 @@
1
+ import dayjs from 'dayjs'
2
+ import { ITopBarInfo } from './top-bar.types'
3
+ import { GetTopBarInfoQueryParam } from './helper'
4
+ import { DTRHelper, IQuickRangeConfig } from './date-time-range'
5
+
6
+ export const QuickRangeConfigs: IQuickRangeConfig[] = [
7
+ { title: 'Last 7 days', ...DTRHelper.dayRange(-7) },
8
+ { title: 'Last 28 days', ...DTRHelper.dayRange(-28) },
9
+ { title: 'Last 90 days', ...DTRHelper.dayRange(-90) },
10
+ { title: 'Last 365 days', ...DTRHelper.dayRange(-365) },
11
+ { title: DTRHelper.yearString(0), ...DTRHelper.yearRange(0), lineAbove: true },
12
+ { title: DTRHelper.yearString(-1), ...DTRHelper.yearRange(-1) },
13
+ { title: DTRHelper.monthString(0), ...DTRHelper.monthRange(0), lineAbove: true },
14
+ { title: DTRHelper.monthString(1), ...DTRHelper.monthRange(-1) },
15
+ { title: DTRHelper.monthString(2), ...DTRHelper.monthRange(-2) }
16
+ ]
17
+
18
+ const GetDefaultSelected = (): IQuickRangeConfig | undefined => {
19
+ try {
20
+ const initial = GetTopBarInfoQueryParam()
21
+
22
+ const index = QuickRangeConfigs.findIndex((x) => x.from === initial.from && x.to === initial.to)
23
+ if (index > -1) return QuickRangeConfigs[index]
24
+
25
+ const from = initial.from ? dayjs(new Date(parseInt(initial.from))) : undefined
26
+ const to = initial.to ? dayjs(new Date(parseInt(initial.to))) : undefined
27
+
28
+ if (!from || !to) return QuickRangeConfigs[1]
29
+
30
+ return {
31
+ title: DTRHelper.getTitle(initial.from, initial.to),
32
+ from: from?.toDate().getTime().toString(),
33
+ to: to?.toDate().getTime().toString()
34
+ }
35
+ } catch (error) {
36
+ console.log(error)
37
+ return QuickRangeConfigs[1]
38
+ }
39
+ }
40
+
41
+ export const DefaultTopBarInfo: ITopBarInfo = {
42
+ QuickRange: GetDefaultSelected()
43
+ }
@@ -0,0 +1,137 @@
1
+ import React, { Component } from 'react'
2
+ import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'
3
+ import { DatePicker, LocalizationProvider } from '@mui/x-date-pickers'
4
+ import { alpha, Box, Button, Collapse, Typography } from '@mui/material'
5
+ import dayjs from 'dayjs'
6
+ import { DTRHelper } from './helpers'
7
+ import { IQuickRangeConfig } from './types'
8
+ import CreateFormBase from '../../../form/create.form-base'
9
+ import { FormValidator, getErrorMessage, SingleRuleValidate } from '../../../form'
10
+
11
+ const FormatString = 'MM/DD/YYYY'
12
+
13
+ const ParseDayjs = (value?: string) => {
14
+ return value ? dayjs(value, FormatString) : undefined
15
+ }
16
+
17
+ const FormBaseInstance = CreateFormBase<IQuickRangeConfig>({
18
+ validate: new FormValidator({
19
+ from: {
20
+ Rules: [
21
+ { rule: SingleRuleValidate.Required },
22
+ {
23
+ rule: SingleRuleValidate.Custom,
24
+ message: 'DateFrom must precede DateTo',
25
+ Value: (value, model) => {
26
+ const from = ParseDayjs(model.from)
27
+ const to = ParseDayjs(model.to)
28
+ return !!to?.isBefore(from)
29
+ }
30
+ }
31
+ ]
32
+ },
33
+ to: { Rules: [{ rule: SingleRuleValidate.Required }] }
34
+ })
35
+ })
36
+
37
+ interface IProps {
38
+ data?: IQuickRangeConfig
39
+ onChangeRange?: (value: IQuickRangeConfig) => void
40
+ }
41
+
42
+ export default class AbsoluteTimeRage extends Component<IProps> {
43
+ render() {
44
+ return (
45
+ <Box sx={{ flex: 1 }}>
46
+ <FormBaseInstance.Form onSubmit={this.handleApply}>
47
+ <Typography variant='subtitle1' sx={{ fontWeight: 600, color: alpha('#000000', 0.7) }}>
48
+ Absolute time range
49
+ </Typography>
50
+ {this.dateTimeRangePickerRanges()}
51
+ {FormBaseInstance.contextMapping((context) => {
52
+ const eMessage = getErrorMessage(context.messageErrors, 'from')
53
+ const isDisabled = Object.keys(context.messageErrors).length > 0
54
+ return (
55
+ <>
56
+ <Collapse in={!!eMessage.error} unmountOnExit>
57
+ <Box sx={{ pt: '6px' }}>
58
+ <Typography variant='caption' sx={{ color: '#d32f2f', fontSize: '0.65rem' }}>
59
+ {eMessage.message}
60
+ </Typography>
61
+ </Box>
62
+ </Collapse>
63
+ <Box sx={{ marginTop: '9px' }}>
64
+ <Button
65
+ disabled={isDisabled}
66
+ size='small'
67
+ variant='contained'
68
+ color='primary'
69
+ type='submit'
70
+ sx={{ textTransform: 'unset !important' }}
71
+ >
72
+ Apply time range
73
+ </Button>
74
+ </Box>
75
+ </>
76
+ )
77
+ })}
78
+ </FormBaseInstance.Form>
79
+ </Box>
80
+ )
81
+ }
82
+ date1Ref = React.createRef<HTMLInputElement>()
83
+ date2Ref = React.createRef<HTMLInputElement>()
84
+ dateTimeRangePickerRanges() {
85
+ return FormBaseInstance.contextMapping((context) => {
86
+ const from = DTRHelper.parseDayJS(this.props.data?.from)
87
+ const to = DTRHelper.parseDayJS(this.props.data?.to)
88
+ const eMessage = getErrorMessage(context.messageErrors, 'from')
89
+ return (
90
+ <LocalizationProvider dateAdapter={AdapterDayjs}>
91
+ <Typography variant='caption' sx={{ fontWeight: 600, color: alpha('#000000', 0.7), mt: '6px', display: 'block' }}>
92
+ from:
93
+ </Typography>
94
+ <DatePicker
95
+ name='from'
96
+ key={this.props.data?.from ? this.props.data.from : 'from'}
97
+ inputRef={this.date1Ref}
98
+ defaultValue={from}
99
+ maxDate={dayjs()}
100
+ slotProps={{ textField: { size: 'small', placeholder: FormatString, error: eMessage.error } }}
101
+ onChange={(d) => {
102
+ if (this.date1Ref.current && d) {
103
+ this.date1Ref.current.value = d.format(FormatString)
104
+ context.onBlur('from')
105
+ }
106
+ }}
107
+ />
108
+ <Typography variant='caption' sx={{ fontWeight: 600, color: alpha('#000000', 0.7), mt: '6px', display: 'block' }}>
109
+ to:
110
+ </Typography>
111
+ <DatePicker
112
+ name='to'
113
+ key={this.props.data?.to ? this.props.data.to : 'to'}
114
+ inputRef={this.date2Ref}
115
+ defaultValue={to}
116
+ maxDate={dayjs()}
117
+ slotProps={{ textField: { size: 'small', placeholder: FormatString, error: eMessage.error } }}
118
+ onChange={(d) => {
119
+ if (this.date2Ref.current && d) {
120
+ this.date2Ref.current.value = d.format(FormatString)
121
+ context.onBlur('to')
122
+ context.onBlur('from')
123
+ }
124
+ }}
125
+ />
126
+ </LocalizationProvider>
127
+ )
128
+ })
129
+ }
130
+
131
+ handleApply = async (value: Partial<IQuickRangeConfig>) => {
132
+ const from = ParseDayjs(value.from)?.startOf('day').toDate().getTime().toString()
133
+ const to = ParseDayjs(value.to)?.endOf('day').toDate().getTime().toString()
134
+ const item: IQuickRangeConfig = { from, to, title: DTRHelper.getTitle(from, to) }
135
+ this.props.onChangeRange && this.props.onChangeRange(item)
136
+ }
137
+ }
@@ -0,0 +1,126 @@
1
+ import dayjs from 'dayjs'
2
+ import { IQuickRangeConfig, IRange } from './types'
3
+
4
+ type TDateTimeKetType = /** 'minute' | 'hour' | */ 'day' | 'month' | 'year'
5
+ export const MapDateTimeKey = (count: number, type?: TDateTimeKetType) => {
6
+ if (count == 0) return 'now'
7
+ const value = count.toString()
8
+ switch (type) {
9
+ // case 'minute':
10
+ // return `now${value}m`
11
+ // case 'hour':
12
+ // return `now${value}h`
13
+ case 'day':
14
+ return `now${value}d`
15
+ case 'month':
16
+ return `now${value}M`
17
+ case 'year':
18
+ return `now${value}y`
19
+ default:
20
+ break
21
+ }
22
+ }
23
+
24
+ class DTRHelperBase {
25
+ formatString = 'MM/DD/YYYY'
26
+
27
+ /**
28
+ * getTitle generates a formatted date range string based on the input dates.
29
+ * @param from - Start date as a string in milliseconds.
30
+ * @param to - End date as a string in milliseconds.
31
+ * @param quickRanges - quickRanges as a ```QuickRangeConfig[]```.
32
+ * @returns Formatted date range or quick range title or fallback string for invalid/undefined values.
33
+ */
34
+ getTitle = (from?: string, to?: string, quickRanges?: IQuickRangeConfig[]) => {
35
+ const quickRangeItem = quickRanges?.find((x) => x.from === from && x.to === to)
36
+ if (!!quickRangeItem) {
37
+ return quickRangeItem.title
38
+ }
39
+
40
+ const fromDate = this.parseDayJS(from)?.format(this.formatString)
41
+ const toDate = this.parseDayJS(to)?.format(this.formatString)
42
+ if (fromDate && toDate) {
43
+ return `${fromDate} - ${toDate}`
44
+ } else if (!fromDate && toDate) {
45
+ return `Until ${toDate}`
46
+ } else if (fromDate && !toDate) {
47
+ return `Starting from ${fromDate}`
48
+ } else {
49
+ return 'Custom'
50
+ }
51
+ }
52
+
53
+ /**
54
+ * getTime converts a formatted date string into a timestamp in milliseconds.
55
+ * Returns the timestamp as a string or NaN if the date is invalid.
56
+ * @param value - Date string in the format 'MM/DD/YYYY'.
57
+ * @returns Timestamp in milliseconds as a string.
58
+ */
59
+ getTime = (value: string, options?: (d: dayjs.Dayjs) => dayjs.Dayjs) => {
60
+ let date = dayjs(value, this.formatString)
61
+ if (!!options) {
62
+ date = options(date)
63
+ }
64
+ return date.isValid() ? date.toDate().getTime().toString() : 'NaN' // Return 'NaN' if the date is invalid
65
+ }
66
+
67
+ /**
68
+ * parseDayJS parses a date in milliseconds into a dayjs object.
69
+ * Returns undefined if the date is invalid or if parsing fails.
70
+ * @param value - String representing a date in milliseconds or other formats.
71
+ * @returns A valid dayjs object or undefined if invalid.
72
+ */
73
+ parseDayJS = (value?: string) => {
74
+ if (!value || isNaN(parseInt(value))) return undefined // Return undefined for non-numeric or empty values
75
+ const parsedDate = dayjs(new Date(parseInt(value)))
76
+ return parsedDate.isValid() ? parsedDate : undefined // Return undefined if the date is invalid
77
+ }
78
+
79
+ dayRange = (range: number = 0): Required<IRange> => {
80
+ const currentDate = dayjs()
81
+ const targetDay = currentDate.subtract(Math.abs(range) - 1, 'day')
82
+ return {
83
+ from: targetDay.startOf('day').toDate().getTime().toString(),
84
+ to: currentDate.endOf('day').toDate().getTime().toString()
85
+ }
86
+ }
87
+
88
+ monthRange = (range: number = 0): Required<IRange> => {
89
+ const currentDate = dayjs()
90
+ const targetMonth = currentDate.subtract(Math.abs(range), 'month')
91
+ let to = targetMonth.endOf('month').toDate().getTime().toString()
92
+ if (currentDate.isSame(targetMonth, 'month')) {
93
+ to = currentDate.endOf('day').toDate().getTime().toString()
94
+ }
95
+ return {
96
+ from: targetMonth.startOf('month').toDate().getTime().toString(),
97
+ to
98
+ }
99
+ }
100
+
101
+ monthString = (range: number = 0) => {
102
+ const currentDate = dayjs()
103
+ const targetYear = currentDate.subtract(Math.abs(range), 'month')
104
+ if (currentDate.year() === targetYear.year()) return targetYear.format('MMMM')
105
+ return targetYear.format('MMMM YYYY')
106
+ }
107
+
108
+ yearRange = (range: number = 0): Required<IRange> => {
109
+ const currentDate = dayjs()
110
+ const targetYear = currentDate.subtract(Math.abs(range), 'years')
111
+ let to = targetYear.endOf('year')
112
+ if (currentDate.year() === targetYear.year()) {
113
+ to = currentDate.endOf('day')
114
+ }
115
+ return {
116
+ from: targetYear.startOf('year').toDate().getTime().toString(),
117
+ to: to.toDate().getTime().toString()
118
+ }
119
+ }
120
+
121
+ yearString = (range: number = 0) => {
122
+ const targetYear = dayjs().subtract(Math.abs(range), 'years')
123
+ return targetYear.year().toString()
124
+ }
125
+ }
126
+ export const DTRHelper = new DTRHelperBase()
@@ -0,0 +1,62 @@
1
+ import React, { Component } from 'react'
2
+ import { Box, Divider, Stack, styled } from '@mui/material'
3
+ import { DTRHelper } from './helpers'
4
+ import { IQuickRangeConfig } from './types'
5
+ import MenuWrap, { IMenuWrap } from './menu-wrap'
6
+ import { UTCTime } from './units'
7
+ import QuickRanges from './quick-ranges'
8
+ import AbsoluteTimeRage from './absolute-time-rage'
9
+
10
+ interface IProps {
11
+ data: IQuickRangeConfig[]
12
+ defaultSelected?: IQuickRangeConfig
13
+ onChange?: (value: IQuickRangeConfig) => void
14
+ }
15
+ interface IState {
16
+ selected?: IQuickRangeConfig
17
+ }
18
+ export default class DateTimeRange extends Component<IProps, IState> {
19
+ configs: IQuickRangeConfig[]
20
+ constructor(props: IProps) {
21
+ super(props)
22
+ this.configs = props.data
23
+ this.state = { selected: props.defaultSelected }
24
+ }
25
+
26
+ refMenuWrap: IMenuWrap | null = null
27
+ render() {
28
+ const obj = this.getTitle()
29
+ return (
30
+ <MenuWrap title={obj.text} subTitle={obj.sub} ref={(ref) => (this.refMenuWrap = ref)}>
31
+ <Wrap>
32
+ <Box sx={{ display: 'flex', alignItems: 'stretch', flex: 1 }}>
33
+ <AbsoluteTimeRage data={this.state.selected} onChangeRange={this.handleSelectItem} />
34
+ <Divider flexItem orientation='vertical' sx={{ m: '0 6px 3px' }} />
35
+ <QuickRanges data={this.configs} onSelect={this.handleSelectItem} selectedValue={this.state.selected} />
36
+ </Box>
37
+ <Divider />
38
+ <UTCTime />
39
+ </Wrap>
40
+ </MenuWrap>
41
+ )
42
+ }
43
+ handleSelectItem = (item: IQuickRangeConfig) => {
44
+ this.props.onChange && this.props.onChange(item)
45
+ this.setState({ selected: item })
46
+ this.refMenuWrap?.close()
47
+ }
48
+
49
+ getTitle = () => ({
50
+ text: DTRHelper.getTitle(this.state.selected?.from, this.state.selected?.to, this.props.data),
51
+ sub: DTRHelper.getTitle(this.state.selected?.from, this.state.selected?.to)
52
+ })
53
+ }
54
+
55
+ const Wrap = styled(Stack)({
56
+ padding: '9px 9px 0',
57
+ height: '100%',
58
+ overflow: 'hidden'
59
+ })
60
+
61
+ export * from './types'
62
+ export * from './helpers'
@@ -0,0 +1,101 @@
1
+ import React, { Component, PropsWithChildren } from 'react'
2
+ import { Button, Menu, SxProps, Theme, Tooltip, styled } from '@mui/material'
3
+ import AccessTimeIcon from '@mui/icons-material/AccessTime'
4
+ import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
5
+
6
+ interface IProps {
7
+ title?: string
8
+ subTitle?: string
9
+ }
10
+
11
+ interface IState {
12
+ anchorEl: null | HTMLElement
13
+ }
14
+ export interface IMenuWrap {
15
+ close: () => void
16
+ }
17
+ export default class MenuWrap extends Component<PropsWithChildren<IProps>, IState> implements IMenuWrap {
18
+ constructor(props: IProps) {
19
+ super(props)
20
+ this.state = { anchorEl: null }
21
+ }
22
+ render() {
23
+ const { anchorEl } = this.state
24
+ const isOpen = Boolean(anchorEl)
25
+
26
+ return (
27
+ <>
28
+ {this.renderTooltip(
29
+ <CustomButton
30
+ variant='text'
31
+ color='inherit'
32
+ onClick={this.onOpen}
33
+ startIcon={<AccessTimeIcon />}
34
+ endIcon={<ExpandMoreIcon sx={{ transition: 'linear 0.1s', transform: `rotate(${isOpen ? -180 : 0}deg)` }} />}
35
+ sx={isOpen ? { backgroundColor: 'rgba(0, 0, 0, 0.04)' } : {}}
36
+ >
37
+ {this.props.title || 'Date time range'}
38
+ </CustomButton>
39
+ )}
40
+ <Menu
41
+ keepMounted
42
+ anchorEl={anchorEl}
43
+ anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
44
+ transformOrigin={{ vertical: 'top', horizontal: 'right' }}
45
+ slotProps={{ paper: { elevation: 0, sx: sxPaperProps } }}
46
+ open={isOpen}
47
+ onClose={this.close}
48
+ MenuListProps={{ component: 'div', sx: { height: '100%', padding: 0 } }}
49
+ >
50
+ {this.props.children}
51
+ </Menu>
52
+ </>
53
+ )
54
+ }
55
+
56
+ renderTooltip = (child: JSX.Element) => {
57
+ const { title, subTitle } = this.props
58
+ const isTooltip = !!subTitle && title !== subTitle
59
+ if (!isTooltip) return child
60
+ return (
61
+ <Tooltip title={this.props.subTitle} placement='left' arrow>
62
+ {child}
63
+ </Tooltip>
64
+ )
65
+ }
66
+
67
+ onOpen = (event: React.MouseEvent<HTMLElement>) => this.setState({ ...this.state, anchorEl: event.currentTarget })
68
+ close = () => this.setState({ ...this.state, anchorEl: null })
69
+ }
70
+
71
+ const sxPaperProps: SxProps<Theme> = {
72
+ overflow: 'visible',
73
+ filter: 'drop-shadow(0px 2px 8px rgba(99, 99, 99, 0.2))',
74
+ marginTop: '10px',
75
+ width: 'calc(100vw - 24px)',
76
+ maxWidth: '550px',
77
+ height: 'calc(100vh - 24px)',
78
+ maxHeight: '420px',
79
+ '&:before': {
80
+ content: '""',
81
+ display: 'block',
82
+ position: 'absolute',
83
+ top: 0,
84
+ right: 14,
85
+ width: 10,
86
+ height: 10,
87
+ backgroundColor: 'background.paper',
88
+ transform: 'translateY(-50%) rotate(45deg)',
89
+ zIndex: 0
90
+ }
91
+ }
92
+
93
+ const CustomButton = styled(Button)({
94
+ textTransform: 'unset',
95
+ fontWeight: 600,
96
+ gap: '6px',
97
+ paddingLeft: '18px',
98
+ paddingRight: '18px',
99
+ minWidth: '220px',
100
+ justifyContent: 'space-between'
101
+ })