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,161 @@
1
+ import React, { Component } from 'react'
2
+ import { alpha, Box, BoxProps, Button, Collapse, Divider, Fade } from '@mui/material'
3
+ import { IconButton, InputAdornment, Stack, styled, TextField, Typography } from '@mui/material'
4
+ import ClearIcon from '@mui/icons-material/Clear'
5
+ import SearchIcon from '@mui/icons-material/Search'
6
+ import { IQuickRangeConfig } from './types'
7
+
8
+ interface IProps {
9
+ selectedValue?: IQuickRangeConfig
10
+ data: IQuickRangeConfig[]
11
+ onSelect: (item: IQuickRangeConfig) => void
12
+ }
13
+
14
+ interface IState {
15
+ searchKey: string
16
+ }
17
+
18
+ export default class QuickRanges extends Component<IProps, IState> {
19
+ constructor(props: IProps) {
20
+ super(props)
21
+ this.state = { searchKey: '' }
22
+ }
23
+ render = () => {
24
+ const data = this.getData()
25
+ return (
26
+ <Stack sx={{ padding: '2px 0', width: '235px', gap: '2px' }}>
27
+ <TextField
28
+ placeholder='Search quick ranges'
29
+ size='small'
30
+ name='search-pick-ranges'
31
+ value={this.state.searchKey}
32
+ onChange={this.handleChangeSearch}
33
+ InputProps={{
34
+ startAdornment: (
35
+ <InputAdornment position='start'>
36
+ <SearchIcon fontSize='small' />
37
+ </InputAdornment>
38
+ ),
39
+ endAdornment: (
40
+ <Fade in={!!this.state.searchKey}>
41
+ <InputAdornment position='end' sx={{ mr: '-8px' }}>
42
+ <IconButton size='small' onClick={() => this.setState({ searchKey: '' })}>
43
+ <ClearIcon fontSize='small' />
44
+ </IconButton>
45
+ </InputAdornment>
46
+ </Fade>
47
+ )
48
+ }}
49
+ />
50
+ <Collapse in={data.length < 1} unmountOnExit>
51
+ <TypographyNotFoundWrap>
52
+ <Typography variant='caption' sx={{ fontWeight: 600, color: alpha('#000000', 0.6) }}>
53
+ Not found
54
+ </Typography>
55
+ </TypographyNotFoundWrap>
56
+ </Collapse>
57
+ {this.renderQuickRanges(data)}
58
+ </Stack>
59
+ )
60
+ }
61
+ renderQuickRanges = (items: IQuickRangeConfig[]) => (
62
+ <QuickRangeWrap>
63
+ {this.renderQuickRangeCustom(items, this.props.selectedValue)}
64
+ {items.map((item, index) => (
65
+ <React.Fragment key={item.title?.toString() + index}>
66
+ {item.lineAbove && <Divider sx={{ my: '2px' }} />}
67
+ <QuickRangeItem
68
+ {...{ component: 'div', className: this.getClassNameItem(item) }}
69
+ color='inherit'
70
+ size='small'
71
+ onClick={() => this.props.onSelect(item)}
72
+ >
73
+ <Typography variant='subtitle2' sx={{ fontWeight: 600, color: alpha('#000000', 0.6) }}>
74
+ {item.title}
75
+ </Typography>
76
+ </QuickRangeItem>
77
+ </React.Fragment>
78
+ ))}
79
+ <Box sx={{ height: '2rem' }} />
80
+ </QuickRangeWrap>
81
+ )
82
+ renderQuickRangeCustom = (items: IQuickRangeConfig[], selected?: IQuickRangeConfig) => {
83
+ const check = !items.some((x) => x.from === selected?.from && x.to === selected?.to)
84
+ return (
85
+ <Collapse in={check} sx={{ transitionDelay: '500ms' }}>
86
+ <Box>
87
+ <QuickRangeItem {...{ component: 'div', className: QuickRangeItemActivatedName }} color='inherit' size='small'>
88
+ <Typography variant='subtitle2' sx={{ fontWeight: 600, color: alpha('#000000', 0.6) }}>
89
+ Custom
90
+ </Typography>
91
+ </QuickRangeItem>
92
+ <Divider sx={{ my: '2px' }} />
93
+ </Box>
94
+ </Collapse>
95
+ )
96
+ }
97
+
98
+ handleChangeSearch: React.ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement> = (e) => {
99
+ this.setState({ searchKey: e.currentTarget.value })
100
+ }
101
+
102
+ getClassNameItem = (item: IQuickRangeConfig) => {
103
+ const selected = this.props.selectedValue
104
+ const check = !!selected && selected?.from === item?.from && selected?.to === item?.to
105
+ return check ? QuickRangeItemActivatedName : ''
106
+ }
107
+ getData = () => {
108
+ if (!!this.state.searchKey) {
109
+ return this.props.data.filter((x) => {
110
+ const t1 = x.title.trim().toLocaleLowerCase()
111
+ const t2 = this.state.searchKey.trim().toLocaleLowerCase()
112
+ return t1.includes(t2)
113
+ })
114
+ }
115
+ return this.props.data
116
+ }
117
+ }
118
+
119
+ const QuickRangeWrap = styled(({ children, ...p }: BoxProps) => (
120
+ <Box {...p}>
121
+ <Box>{children}</Box>
122
+ </Box>
123
+ ))({
124
+ flex: 1,
125
+ position: 'relative',
126
+ marginRight: '-7px',
127
+ '& > div': {
128
+ overflow: 'auto',
129
+ position: 'absolute',
130
+ top: 0,
131
+ left: 0,
132
+ width: '100%',
133
+ height: '100%',
134
+ padding: '3px 3px 0 0 '
135
+ }
136
+ })
137
+ const QuickRangeItemActivatedName = 'activated'
138
+ const QuickRangeItem = styled(Button)({
139
+ display: 'block',
140
+ padding: '7px 9px',
141
+ textTransform: 'unset',
142
+ justifyContent: 'flex-start',
143
+ '&.hover': {
144
+ backgroundColor: 'rgba(204, 204, 220, 0.16)!important',
145
+ cursor: 'pointer'
146
+ },
147
+ [`&.${QuickRangeItemActivatedName}`]: {
148
+ backgroundColor: 'rgba(204, 204, 220, 0.13)',
149
+ pointerEvents: 'none',
150
+ '& .MuiTypography-root': {
151
+ color: '#397ce0'
152
+ }
153
+ }
154
+ })
155
+
156
+ const TypographyNotFoundWrap = styled(Box)({
157
+ margin: '6px 0',
158
+ backgroundColor: alpha('#000000', 0.05),
159
+ borderRadius: '6px',
160
+ padding: '5px 9px'
161
+ })
@@ -0,0 +1,9 @@
1
+ export interface IRange {
2
+ from?: string
3
+ to?: string
4
+ }
5
+
6
+ export interface IQuickRangeConfig extends IRange {
7
+ title: string
8
+ lineAbove?: boolean
9
+ }
@@ -0,0 +1,18 @@
1
+ import React, { FC } from 'react'
2
+ import { alpha, Box, Typography } from '@mui/material'
3
+
4
+ //#region UTCTime
5
+ export const UTCTime: FC = () => (
6
+ <Box sx={{ display: 'flex', alignItems: 'center', gap: '6px', padding: '6px 0' }}>
7
+ <Typography variant='subtitle2' sx={{ fontWeight: 600, lineHeight: 1, color: alpha('#000000', 0.7) }}>
8
+ Date and time ranges
9
+ </Typography>
10
+ {/* <Typography variant='subtitle2' sx={{ fontWeight: 600, lineHeight: 1, color: alpha('#000000', 0.7) }}>
11
+ Browser Time
12
+ </Typography>
13
+ <Typography variant='caption' sx={{ lineHeight: 1 }}>
14
+ Ha Noi, VietNam
15
+ </Typography> */}
16
+ </Box>
17
+ )
18
+ //#endregion
@@ -0,0 +1,25 @@
1
+ import queryString from 'query-string'
2
+ import { ITopBarInfo } from './top-bar.types'
3
+ import { IGrafanaDashBoardOptions } from './types'
4
+ import { QueryParam } from '../../utils'
5
+
6
+ interface IOptions extends ITopBarInfo, Omit<IGrafanaDashBoardOptions, 'from' | 'to'> {}
7
+
8
+ export const TopBarInfoToQueryParam = (urlBase: string, options?: IOptions) => {
9
+ const obj: IGrafanaDashBoardOptions = {}
10
+ if (!!options?.orgId) obj.orgId = options.orgId
11
+ if (!!options?.QuickRange) {
12
+ obj.from = options.QuickRange.from
13
+ obj.to = options.QuickRange.to
14
+ }
15
+ return `${urlBase}?${queryString.stringify(obj)}`
16
+ }
17
+
18
+ export const GetTopBarInfoQueryParam = (): IGrafanaDashBoardOptions => {
19
+ try {
20
+ const obj = QueryParam.Gets<IGrafanaDashBoardOptions>('from', 'to')
21
+ return obj as IGrafanaDashBoardOptions
22
+ } catch (error) {
23
+ return {}
24
+ }
25
+ }
@@ -0,0 +1,79 @@
1
+ import React from 'react'
2
+ import { ITopBarInfo } from './top-bar.types'
3
+ import { DefaultTopBarInfo } from './configs'
4
+ import { IGrafanaDashBoardOptions } from './types'
5
+ import { IQuickRangeConfig } from './date-time-range'
6
+ import { QueryParam } from '../../utils'
7
+
8
+ const useQueryParam = (data: ITopBarInfo, activated?: boolean) => {
9
+ React.useEffect(() => {
10
+ if (activated === true) {
11
+ const { QuickRange } = data
12
+ QueryParam.Patch<IGrafanaDashBoardOptions>({ from: QuickRange?.from, to: QuickRange?.to })
13
+ }
14
+ }, [data, activated])
15
+ }
16
+
17
+ const useLoading = () => {
18
+ const [isLoading, setIsLoading] = React.useState(true)
19
+ const loading = () => setIsLoading(true)
20
+ const unloading = () => setIsLoading(false)
21
+ return [isLoading, loading, unloading] as [boolean, () => void, () => void]
22
+ }
23
+
24
+ const useTopBarInfo = () => {
25
+ const [topBarInfo, setTopBarInfo] = React.useState<ITopBarInfo>(DefaultTopBarInfo)
26
+ const topBarInfoChange = (value?: IQuickRangeConfig) => {
27
+ const obj = { ...topBarInfo }
28
+ obj.QuickRange = value
29
+ setTopBarInfo(obj)
30
+ }
31
+ return [topBarInfo, topBarInfoChange] as [ITopBarInfo, (value?: IQuickRangeConfig, callback?: () => void) => void]
32
+ }
33
+
34
+ const ScrollBarCustom = `
35
+ /* width */
36
+ ::-webkit-scrollbar {
37
+ width: 8px;
38
+ }
39
+ /* Track */
40
+ ::-webkit-scrollbar-track {
41
+ border-radius: 4px;
42
+ background: transparent;
43
+ }
44
+ :hover::-webkit-scrollbar-track {
45
+ background: #f1f1f1;
46
+ }
47
+ /* Handle */
48
+ ::-webkit-scrollbar-thumb {
49
+ border-radius: 4px;
50
+ background: rgba(135, 135, 135, 0.15);
51
+ }
52
+ :hover::-webkit-scrollbar-thumb {
53
+ background: #878787;
54
+ }
55
+ /* Handle on hover */
56
+ ::-webkit-scrollbar-thumb:hover {
57
+ background: #606060;
58
+ }
59
+ `
60
+
61
+ const useCustomScrollBar = (iframeRef: React.RefObject<HTMLIFrameElement>) => {
62
+ React.useEffect(() => {
63
+ const doc = iframeRef.current?.contentWindow?.document
64
+ if (!!doc) {
65
+ const st = doc.createElement('style')
66
+ st.innerHTML = ScrollBarCustom
67
+ doc.head.append(st)
68
+ }
69
+ return () => {}
70
+ }, [iframeRef])
71
+ }
72
+
73
+ const GrafanaDashboardHooks = {
74
+ useQueryParam,
75
+ useLoading,
76
+ useTopBarInfo,
77
+ useCustomScrollBar
78
+ }
79
+ export default GrafanaDashboardHooks
@@ -0,0 +1,67 @@
1
+ import * as React from 'react'
2
+ import { SvgIcon, SvgIconProps } from '@mui/material'
3
+
4
+ export const SvgLoading: React.FC<SvgIconProps & { fill?: string }> = (props) => {
5
+ return (
6
+ <SvgIcon {...props}>
7
+ {/* credit: plus icon from https://heroicons.com/ */}
8
+ <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'>
9
+ <circle fill={props.fill} stroke={props.fill} strokeWidth='15' r='15' cx='35' cy='100'>
10
+ <animate
11
+ attributeName='cx'
12
+ calcMode='spline'
13
+ dur='2'
14
+ values='35;165;165;35;35'
15
+ keySplines='0 .1 .5 1;0 .1 .5 1;0 .1 .5 1;0 .1 .5 1'
16
+ repeatCount='indefinite'
17
+ begin='0'
18
+ ></animate>
19
+ </circle>
20
+ <circle fill={props.fill} stroke={props.fill} strokeWidth='15' opacity='.8' r='15' cx='35' cy='100'>
21
+ <animate
22
+ attributeName='cx'
23
+ calcMode='spline'
24
+ dur='2'
25
+ values='35;165;165;35;35'
26
+ keySplines='0 .1 .5 1;0 .1 .5 1;0 .1 .5 1;0 .1 .5 1'
27
+ repeatCount='indefinite'
28
+ begin='0.05'
29
+ ></animate>
30
+ </circle>
31
+ <circle fill={props.fill} stroke={props.fill} strokeWidth='15' opacity='.6' r='15' cx='35' cy='100'>
32
+ <animate
33
+ attributeName='cx'
34
+ calcMode='spline'
35
+ dur='2'
36
+ values='35;165;165;35;35'
37
+ keySplines='0 .1 .5 1;0 .1 .5 1;0 .1 .5 1;0 .1 .5 1'
38
+ repeatCount='indefinite'
39
+ begin='.1'
40
+ ></animate>
41
+ </circle>
42
+ <circle fill={props.fill} stroke={props.fill} strokeWidth='15' opacity='.4' r='15' cx='35' cy='100'>
43
+ <animate
44
+ attributeName='cx'
45
+ calcMode='spline'
46
+ dur='2'
47
+ values='35;165;165;35;35'
48
+ keySplines='0 .1 .5 1;0 .1 .5 1;0 .1 .5 1;0 .1 .5 1'
49
+ repeatCount='indefinite'
50
+ begin='.15'
51
+ ></animate>
52
+ </circle>
53
+ <circle fill={props.fill} stroke={props.fill} strokeWidth='15' opacity='.2' r='15' cx='35' cy='100'>
54
+ <animate
55
+ attributeName='cx'
56
+ calcMode='spline'
57
+ dur='2'
58
+ values='35;165;165;35;35'
59
+ keySplines='0 .1 .5 1;0 .1 .5 1;0 .1 .5 1;0 .1 .5 1'
60
+ repeatCount='indefinite'
61
+ begin='.2'
62
+ ></animate>
63
+ </circle>
64
+ </svg>
65
+ </SvgIcon>
66
+ )
67
+ }
@@ -0,0 +1,120 @@
1
+ import React, { FC, useEffect } from 'react'
2
+ import { Box, Fade, Stack, styled, Typography } from '@mui/material'
3
+ import { SvgLoading } from './icons'
4
+ import { QuickRangeConfigs } from './configs'
5
+ import { TopBarInfoToQueryParam } from './helper'
6
+ import { IGrafanaDashBoardOptions } from './types'
7
+ import TopBar from './top-bar'
8
+ import GrafanaDashboardHooks from './hooks'
9
+
10
+ interface IGrafanaDashboardProps {
11
+ url: string
12
+ title?: string
13
+ options?: IGrafanaDashBoardOptions
14
+ topBar?: boolean
15
+ queryParam?: boolean
16
+ onLoadComplete?: () => void
17
+ }
18
+ export const GrafanaDashboard: FC<IGrafanaDashboardProps> = (props) => {
19
+ const iframeRef = React.useRef<HTMLIFrameElement>(null)
20
+ const [isLoading, loading, unloading] = GrafanaDashboardHooks.useLoading()
21
+ const [topBarInfo, topBarInfoChange] = GrafanaDashboardHooks.useTopBarInfo()
22
+
23
+ GrafanaDashboardHooks.useQueryParam(topBarInfo, props?.queryParam)
24
+ GrafanaDashboardHooks.useCustomScrollBar(iframeRef)
25
+
26
+ // ========= ========= ========= Events ========= ========= =========
27
+ const handleRefresh = () => {
28
+ if (iframeRef.current) {
29
+ loading()
30
+ iframeRef.current.src = iframeRef.current.src
31
+ }
32
+ }
33
+
34
+ // ========= ========= ========= Main ========= ========= =========
35
+ const createUrl = () => {
36
+ const a = document.createElement('a')
37
+ a.href = TopBarInfoToQueryParam(props.url, { ...topBarInfo })
38
+ const url = new URL(a.href)
39
+ const params = new URLSearchParams(url.search)
40
+ // Add or update query parameters
41
+ if (!props.options || !props.options.kiosk) {
42
+ params.set('kiosk', 'true')
43
+ }
44
+ const option = props.options
45
+ if (option) {
46
+ Object.keys(option).forEach((key) => params.set(key, (option as any)[key]))
47
+ }
48
+ // Rebuild the URL with the new parameters
49
+ url.search = params.toString()
50
+ return url
51
+ }
52
+ const url = createUrl()
53
+
54
+ useEffect(() => {
55
+ loading()
56
+ // eslint-disable-next-line react-hooks/exhaustive-deps
57
+ }, [url.toString()])
58
+
59
+ React.useEffect(() => {
60
+ const iframe = iframeRef.current
61
+ const onComplete = () => {
62
+ unloading()
63
+ props.onLoadComplete && props.onLoadComplete()
64
+ }
65
+ if (iframe) iframe.addEventListener('load', onComplete)
66
+ return () => {
67
+ // Clean up event
68
+ if (iframe) iframe.removeEventListener('load', onComplete)
69
+ }
70
+ // eslint-disable-next-line react-hooks/exhaustive-deps
71
+ }, [props, props.onLoadComplete])
72
+
73
+ return (
74
+ <Wrap>
75
+ {props?.topBar === true && (
76
+ <TopBar
77
+ dateTimeRanges={{ data: QuickRangeConfigs, defaultValue: topBarInfo.QuickRange }}
78
+ onDateTimeRangeChange={(x) => {
79
+ topBarInfoChange(x)
80
+ }}
81
+ onRefresh={handleRefresh}
82
+ />
83
+ )}
84
+ <Box sx={{ flex: 1, position: 'relative' }}>
85
+ <Box sx={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }}>
86
+ <IFrame ref={iframeRef} src={url.toString()} title={props.title} />
87
+ </Box>
88
+ </Box>
89
+ <Fade in={isLoading} unmountOnExit>
90
+ <Backdrop>
91
+ <SvgLoading sx={{ fontSize: '6.5rem' }} fill='#fb8c1e' />
92
+ <Typography variant='subtitle2'>Loading . . .</Typography>
93
+ </Backdrop>
94
+ </Fade>
95
+ </Wrap>
96
+ )
97
+ }
98
+
99
+ const IFrame = styled('iframe')({
100
+ border: 0,
101
+ width: '100%',
102
+ height: '100%'
103
+ })
104
+ const Wrap = styled(Stack)({
105
+ flex: 1,
106
+ position: 'relative',
107
+ justifyContent: 'stretch'
108
+ })
109
+ const Backdrop = styled(Box)({
110
+ position: 'absolute',
111
+ top: 0,
112
+ bottom: 0,
113
+ width: '100%',
114
+ height: '100%',
115
+ background: '#fff',
116
+ display: 'flex',
117
+ justifyContent: 'center',
118
+ alignItems: 'center',
119
+ flexDirection: 'column'
120
+ })
@@ -0,0 +1,62 @@
1
+ import React, { Component } from 'react'
2
+ import { Box, Divider, IconButton, styled, Tooltip } from '@mui/material'
3
+ import SyncIcon from '@mui/icons-material/Sync'
4
+ import DateTimeRange, { IQuickRangeConfig } from './date-time-range'
5
+
6
+ export interface ITopBar {
7
+ onRefresh?: () => void
8
+ onDateTimeRangeChange?: (value?: IQuickRangeConfig) => void
9
+ }
10
+
11
+ interface IProps extends ITopBar {
12
+ dateTimeRanges: {
13
+ data: IQuickRangeConfig[]
14
+ defaultValue?: IQuickRangeConfig
15
+ }
16
+ after?: JSX.Element
17
+ before?: JSX.Element
18
+ }
19
+
20
+ export default class TopBar extends Component<IProps> {
21
+ render() {
22
+ return (
23
+ <Wrap>
24
+ {this.props?.after && this.props.after}
25
+ {!!this.props.onDateTimeRangeChange && (
26
+ <DateTimeRange
27
+ data={this.props.dateTimeRanges.data}
28
+ defaultSelected={this.props.dateTimeRanges.defaultValue}
29
+ onChange={this.props.onDateTimeRangeChange}
30
+ />
31
+ )}
32
+ {!!this.props.onRefresh && (
33
+ <>
34
+ <Divider flexItem orientation='vertical' sx={{ m: '6px 0' }} />
35
+ <Tooltip title='Refresh dashboard' arrow>
36
+ <IconButton onClick={this.props.onRefresh}>
37
+ <SyncIcon fontSize='small' />
38
+ </IconButton>
39
+ </Tooltip>
40
+ </>
41
+ )}
42
+ {this.props?.before && this.props.before}
43
+ <Box sx={{ width: '36px' }} />
44
+ </Wrap>
45
+ )
46
+ }
47
+ }
48
+
49
+ export const TopBarheight = 43
50
+ const Wrap = styled(Box)(({ theme }) => ({
51
+ display: 'flex',
52
+ justifyContent: 'end',
53
+ padding: '3px 12px',
54
+ margin: '0 -10px',
55
+ gap: '6px',
56
+ boxShadow: theme.app.boxShadow[1],
57
+ position: 'relative',
58
+ zIndex: 1,
59
+ height: `${TopBarheight}px`,
60
+ alignItems: 'center',
61
+ flex: '0 0 auto'
62
+ }))
@@ -0,0 +1,5 @@
1
+ import { IQuickRangeConfig } from './date-time-range'
2
+
3
+ export interface ITopBarInfo {
4
+ QuickRange?: IQuickRangeConfig
5
+ }
@@ -0,0 +1,8 @@
1
+ export interface IGrafanaDashBoardOptions {
2
+ from?: string
3
+ to?: string
4
+ refresh?: string
5
+ kiosk?: 'tv' | 'true' | 'false'
6
+ theme?: 'light' | 'dark'
7
+ orgId?: number
8
+ }