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.
- package/README.md +54 -0
- package/dist/_virtual/_rollupPluginBabelHelpers.js +431 -0
- package/dist/_virtual/_rollupPluginBabelHelpers.js.map +1 -0
- package/dist/assets/vector-404265a04f4f9c8be1f.webp +0 -0
- package/dist/node_modules/.pnpm/@rollup_plugin-typescript@1_d0d2002d9033600b6738d939bd598bc6/node_modules/tslib/tslib.es6.js +46 -0
- package/dist/node_modules/.pnpm/@rollup_plugin-typescript@1_d0d2002d9033600b6738d939bd598bc6/node_modules/tslib/tslib.es6.js.map +1 -0
- package/dist/src/api-context/alert-global.js +151 -0
- package/dist/src/api-context/alert-global.js.map +1 -0
- package/dist/src/api-context/drawer-global.js +105 -0
- package/dist/src/api-context/drawer-global.js.map +1 -0
- package/dist/src/api-context/global-modal.js +87 -0
- package/dist/src/api-context/global-modal.js.map +1 -0
- package/dist/src/api-context/popover-global.js +102 -0
- package/dist/src/api-context/popover-global.js.map +1 -0
- package/dist/src/api-context/popover.js +86 -0
- package/dist/src/api-context/popover.js.map +1 -0
- package/dist/src/api-context/ui.units.js +21 -0
- package/dist/src/api-context/ui.units.js.map +1 -0
- package/dist/src/components/copy-to-clipboard.js +105 -0
- package/dist/src/components/copy-to-clipboard.js.map +1 -0
- package/dist/src/components/custom.breadcrumbs.js +61 -0
- package/dist/src/components/custom.breadcrumbs.js.map +1 -0
- package/dist/src/components/help-tooltip.js +91 -0
- package/dist/src/components/help-tooltip.js.map +1 -0
- package/dist/src/components/image-with-fallback.js +48 -0
- package/dist/src/components/image-with-fallback.js.map +1 -0
- package/dist/src/components/text-editor.js +117 -0
- package/dist/src/components/text-editor.js.map +1 -0
- package/dist/src/form/create.autocomplete.chips.js +218 -0
- package/dist/src/form/create.autocomplete.chips.js.map +1 -0
- package/dist/src/form/create.date-expired.js +201 -0
- package/dist/src/form/create.date-expired.js.map +1 -0
- package/dist/src/form/create.date-picker.js +125 -0
- package/dist/src/form/create.date-picker.js.map +1 -0
- package/dist/src/form/create.form-base.js +135 -0
- package/dist/src/form/create.form-base.js.map +1 -0
- package/dist/src/form/create.form-comfirm.js +119 -0
- package/dist/src/form/create.form-comfirm.js.map +1 -0
- package/dist/src/form/create.form-grid-layout.js +177 -0
- package/dist/src/form/create.form-grid-layout.js.map +1 -0
- package/dist/src/form/create.form-grid-layout.units.js +39 -0
- package/dist/src/form/create.form-grid-layout.units.js.map +1 -0
- package/dist/src/form/create.input-base.js +260 -0
- package/dist/src/form/create.input-base.js.map +1 -0
- package/dist/src/form/create.input.file.js +74 -0
- package/dist/src/form/create.input.file.js.map +1 -0
- package/dist/src/form/create.select-simple.js +104 -0
- package/dist/src/form/create.select-simple.js.map +1 -0
- package/dist/src/form/create.select-with-api.js +271 -0
- package/dist/src/form/create.select-with-api.js.map +1 -0
- package/dist/src/form/create.text-editor.js +156 -0
- package/dist/src/form/create.text-editor.js.map +1 -0
- package/dist/src/form/dino-form.js +42 -0
- package/dist/src/form/dino-form.js.map +1 -0
- package/dist/src/form/helper.js +157 -0
- package/dist/src/form/helper.js.map +1 -0
- package/dist/src/form/modal-wrapper.js +75 -0
- package/dist/src/form/modal-wrapper.js.map +1 -0
- package/dist/src/form/validator.js +186 -0
- package/dist/src/form/validator.js.map +1 -0
- package/dist/src/hooks/index.js +48 -0
- package/dist/src/hooks/index.js.map +1 -0
- package/dist/src/index.js +26 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/redux/create.hoc-lazy.js +67 -0
- package/dist/src/redux/create.hoc-lazy.js.map +1 -0
- package/dist/src/redux/dino.js +11 -0
- package/dist/src/redux/dino.js.map +1 -0
- package/dist/src/redux/types.js +9 -0
- package/dist/src/redux/types.js.map +1 -0
- package/dist/src/redux/ui.error-page.js +80 -0
- package/dist/src/redux/ui.error-page.js.map +1 -0
- package/dist/src/redux/vector-404.webp.js +4 -0
- package/dist/src/redux/vector-404.webp.js.map +1 -0
- package/dist/src/table/context.js +12 -0
- package/dist/src/table/context.js.map +1 -0
- package/dist/src/table/create.action-row.js +135 -0
- package/dist/src/table/create.action-row.js.map +1 -0
- package/dist/src/table/create.status-cell.js +49 -0
- package/dist/src/table/create.status-cell.js.map +1 -0
- package/dist/src/table/create.table.js +233 -0
- package/dist/src/table/create.table.js.map +1 -0
- package/dist/src/table/custom.filter-operators.js +89 -0
- package/dist/src/table/custom.filter-operators.js.map +1 -0
- package/dist/src/table/dino.js +129 -0
- package/dist/src/table/dino.js.map +1 -0
- package/dist/src/table/helpers.js +116 -0
- package/dist/src/table/helpers.js.map +1 -0
- package/dist/src/table/model-filter.js +23 -0
- package/dist/src/table/model-filter.js.map +1 -0
- package/dist/src/table/toolbar-pannel.js +134 -0
- package/dist/src/table/toolbar-pannel.js.map +1 -0
- package/dist/src/table/ui.buttons.js +60 -0
- package/dist/src/table/ui.buttons.js.map +1 -0
- package/dist/src/table/ui.units.js +201 -0
- package/dist/src/table/ui.units.js.map +1 -0
- package/dist/src/utils/dayjs-config.js +12 -0
- package/dist/src/utils/dayjs-config.js.map +1 -0
- package/dist/src/utils/helpers.js +197 -0
- package/dist/src/utils/helpers.js.map +1 -0
- package/dist/src/utils/json-object.js +38 -0
- package/dist/src/utils/json-object.js.map +1 -0
- package/dist/src/utils/query-param.js +172 -0
- package/dist/src/utils/query-param.js.map +1 -0
- package/package.json +52 -0
- package/rollup.config.js +39 -0
- package/src/@types/global.d.ts +5 -0
- package/src/api-context/alert-global.tsx +174 -0
- package/src/api-context/drawer-global.tsx +116 -0
- package/src/api-context/global-modal.tsx +109 -0
- package/src/api-context/index.ts +13 -0
- package/src/api-context/popover-global.tsx +107 -0
- package/src/api-context/popover.tsx +89 -0
- package/src/api-context/ui.units.tsx +10 -0
- package/src/components/copy-to-clipboard.tsx +86 -0
- package/src/components/custom.breadcrumbs.tsx +67 -0
- package/src/components/help-tooltip.tsx +75 -0
- package/src/components/image-with-fallback.tsx +51 -0
- package/src/components/index.tsx +1 -0
- package/src/components/input-debounce-timer.tsx +138 -0
- package/src/components/loading-buttons.tsx +35 -0
- package/src/components/text-editor.preview.tsx +30 -0
- package/src/components/text-editor.tsx +125 -0
- package/src/form/README.md +55 -0
- package/src/form/create.autocomplete.chips.tsx +199 -0
- package/src/form/create.date-expired.tsx +195 -0
- package/src/form/create.date-picker.tsx +122 -0
- package/src/form/create.form-base.tsx +102 -0
- package/src/form/create.form-comfirm.tsx +83 -0
- package/src/form/create.form-grid-layout.tsx +170 -0
- package/src/form/create.form-grid-layout.units.tsx +37 -0
- package/src/form/create.input-base.tsx +222 -0
- package/src/form/create.input.file.tsx +76 -0
- package/src/form/create.select-simple.tsx +101 -0
- package/src/form/create.select-with-api.tsx +213 -0
- package/src/form/create.text-editor.tsx +161 -0
- package/src/form/dino-form.tsx +40 -0
- package/src/form/helper.ts +132 -0
- package/src/form/index.ts +12 -0
- package/src/form/modal-wrapper.tsx +75 -0
- package/src/form/types.ts +16 -0
- package/src/form/validator.ts +202 -0
- package/src/hooks/index.ts +44 -0
- package/src/index.ts +7 -0
- package/src/lab/create.autocomplete.simple.tsx +57 -0
- package/src/lab/create.dino-store.ts +59 -0
- package/src/lab/create.multi-select-dropdown.tsx +189 -0
- package/src/lab/create.select-mul-with-api/index.tsx +271 -0
- package/src/lab/create.select-mul-with-api/table-custom.tsx +194 -0
- package/src/lab/create.select-mul-with-api/types.ts +26 -0
- package/src/lab/create.select-mul-with-api/ui.units.tsx +163 -0
- package/src/lab/filter-bar/base.tsx +162 -0
- package/src/lab/filter-bar/create.filter-bar.tsx +190 -0
- package/src/lab/filter-bar/create.filter-menu.tsx +156 -0
- package/src/lab/filter-bar/create.filter-panel.tsx +95 -0
- package/src/lab/filter-bar/create.filtered.tsx +41 -0
- package/src/lab/filter-bar/create.sort-menu.tsx +43 -0
- package/src/lab/filter-bar/demo.tsx +50 -0
- package/src/lab/filter-bar/index.ts +6 -0
- package/src/lab/filter-bar/types.ts +105 -0
- package/src/lab/filter-bar/ui.units.tsx +70 -0
- package/src/lab/grafana-dashboard/configs.ts +43 -0
- package/src/lab/grafana-dashboard/date-time-range/absolute-time-rage.tsx +137 -0
- package/src/lab/grafana-dashboard/date-time-range/helpers.ts +126 -0
- package/src/lab/grafana-dashboard/date-time-range/index.tsx +62 -0
- package/src/lab/grafana-dashboard/date-time-range/menu-wrap.tsx +101 -0
- package/src/lab/grafana-dashboard/date-time-range/quick-ranges.tsx +161 -0
- package/src/lab/grafana-dashboard/date-time-range/types.ts +9 -0
- package/src/lab/grafana-dashboard/date-time-range/units.tsx +18 -0
- package/src/lab/grafana-dashboard/helper.ts +25 -0
- package/src/lab/grafana-dashboard/hooks.tsx +79 -0
- package/src/lab/grafana-dashboard/icons.tsx +67 -0
- package/src/lab/grafana-dashboard/index.tsx +120 -0
- package/src/lab/grafana-dashboard/top-bar.tsx +62 -0
- package/src/lab/grafana-dashboard/top-bar.types.ts +5 -0
- package/src/lab/grafana-dashboard/types.ts +8 -0
- package/src/lab/media-player.core1.tsx +273 -0
- package/src/lab/media-player.muted.tsx +62 -0
- package/src/lab/media-player.units.ts +80 -0
- package/src/lab/table-grid/create.table-grid.tsx +183 -0
- package/src/lab/table-grid/demo.tsx +53 -0
- package/src/lab/table-grid/dino.tsx +8 -0
- package/src/lab/table-grid/helpers.tsx +11 -0
- package/src/lab/table-grid/index.ts +3 -0
- package/src/lab/table-grid/item-actions.tsx +138 -0
- package/src/lab/table-grid/toolbar-pannel.tsx +98 -0
- package/src/lab/table-grid/types.ts +68 -0
- package/src/redux/create.hoc-lazy.tsx +80 -0
- package/src/redux/dino.ts +9 -0
- package/src/redux/index.ts +6 -0
- package/src/redux/types.ts +27 -0
- package/src/redux/ui.error-page.tsx +62 -0
- package/src/redux/ui.units.tsx +41 -0
- package/src/redux/vector-404.webp +0 -0
- package/src/table/context.tsx +16 -0
- package/src/table/create.action-row.tsx +91 -0
- package/src/table/create.status-cell.tsx +51 -0
- package/src/table/create.table.tsx +239 -0
- package/src/table/custom.filter-operators.ts +94 -0
- package/src/table/dino.tsx +120 -0
- package/src/table/helpers.ts +94 -0
- package/src/table/index.ts +13 -0
- package/src/table/model-filter.ts +43 -0
- package/src/table/toolbar-pannel.tsx +106 -0
- package/src/table/types.ts +50 -0
- package/src/table/ui.buttons.tsx +54 -0
- package/src/table/ui.units.tsx +189 -0
- package/src/utils/dayjs-config.ts +13 -0
- package/src/utils/helpers.ts +171 -0
- package/src/utils/index.ts +7 -0
- package/src/utils/json-object.ts +29 -0
- package/src/utils/mfe-events.tsx +34 -0
- package/src/utils/query-param.ts +129 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import React, { Component, ComponentType, ReactNode } from 'react'
|
|
2
|
+
import { Box, colors, IconButton, List, ListItem, ListItemButton, ListItemIcon, ListItemProps, ListItemText, styled } from '@mui/material'
|
|
3
|
+
import EditIcon from '@mui/icons-material/Edit'
|
|
4
|
+
import MoreVertIcon from '@mui/icons-material/MoreVert'
|
|
5
|
+
import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline'
|
|
6
|
+
import { ClosePopover, GlobalModalState, MapGlobalModalContext, PopoverGlobal } from '../../api-context'
|
|
7
|
+
|
|
8
|
+
export type TableGridItemActionType = 'Edit' | 'Delete'
|
|
9
|
+
|
|
10
|
+
const mapIcons: { [key in TableGridItemActionType]: ReactNode } = {
|
|
11
|
+
Edit: <EditIcon fontSize='small' color='primary' />,
|
|
12
|
+
Delete: <DeleteOutlineIcon fontSize='small' color='error' />
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface TableGridItemActionsProps<T> {
|
|
16
|
+
value: T
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
type FormRenderFunc<T> = (value: T) => React.ReactNode
|
|
20
|
+
|
|
21
|
+
interface ListItemDef<T> {
|
|
22
|
+
name: string
|
|
23
|
+
icon?: ReactNode
|
|
24
|
+
/** Whether this item should trigger a close action when clicked. @default true */
|
|
25
|
+
closableOnClick?: boolean
|
|
26
|
+
/** Handler called when item is clicked */
|
|
27
|
+
onClick?: (event: React.MouseEvent<HTMLLIElement, MouseEvent>, value: T) => void
|
|
28
|
+
listItemProps?: ListItemProps
|
|
29
|
+
/**
|
|
30
|
+
* Optional custom ReactNode to override the entire ListItem UI.
|
|
31
|
+
* If provided, this will be rendered instead of the default ListItem structure
|
|
32
|
+
* (icon + text + click behavior).
|
|
33
|
+
*/
|
|
34
|
+
override?: ComponentType<{ onClose?: ClosePopover }>
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface TableGridItemActionsConfig<T> {
|
|
38
|
+
formEdit?: FormRenderFunc<T>
|
|
39
|
+
formDelete?: FormRenderFunc<T>
|
|
40
|
+
buttonEditConfig?: GlobalModalState
|
|
41
|
+
buttonDeleteConfig?: GlobalModalState
|
|
42
|
+
menuList?: {
|
|
43
|
+
before?: SingleOrArray<ListItemDef<T>>
|
|
44
|
+
after?: ListItemDef<T>
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface IProps<T> extends TableGridItemActionsProps<T>, TableGridItemActionsConfig<T> {}
|
|
49
|
+
|
|
50
|
+
export function CreateTableGridItemActions<T>() {
|
|
51
|
+
class TableGridItemActions extends Component<IProps<T>> {
|
|
52
|
+
render() {
|
|
53
|
+
if (!this.isVisible()) return <></>
|
|
54
|
+
return (
|
|
55
|
+
<Wrap>
|
|
56
|
+
<IconButton
|
|
57
|
+
size='small'
|
|
58
|
+
onClick={(e) => {
|
|
59
|
+
PopoverGlobal.Api.open({
|
|
60
|
+
anchorEl: e.currentTarget,
|
|
61
|
+
popoverProps: { anchorOrigin: { vertical: 'top', horizontal: 'right' }, transformOrigin: { vertical: 'top', horizontal: 'right' } },
|
|
62
|
+
content: (
|
|
63
|
+
<List>
|
|
64
|
+
{this.renderItems(this.props.menuList?.before)}
|
|
65
|
+
{this.renderItemWithForm('Edit', this.props.formEdit, this.props.buttonEditConfig)}
|
|
66
|
+
{this.renderItemWithForm('Delete', this.props.formDelete, this.props.buttonEditConfig ?? { backdropActivated: true })}
|
|
67
|
+
{this.renderItems(this.props.menuList?.after)}
|
|
68
|
+
</List>
|
|
69
|
+
)
|
|
70
|
+
})
|
|
71
|
+
}}
|
|
72
|
+
>
|
|
73
|
+
<MoreVertIcon fontSize='small' />
|
|
74
|
+
</IconButton>
|
|
75
|
+
</Wrap>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
isVisible = () => {
|
|
80
|
+
return !!this.props.formEdit || !!this.props.formDelete
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
renderItems = (value?: SingleOrArray<ListItemDef<T>>) => {
|
|
84
|
+
if (!value) return <></>
|
|
85
|
+
const list = Array.isArray(value) ? value : [value]
|
|
86
|
+
return list.map((item, index) => {
|
|
87
|
+
const key = item.name + index
|
|
88
|
+
const { override: Override } = item
|
|
89
|
+
if (Override) return <Override key={key} onClose={PopoverGlobal.Api.close} />
|
|
90
|
+
return (
|
|
91
|
+
<ListItem
|
|
92
|
+
key={key}
|
|
93
|
+
disablePadding
|
|
94
|
+
sx={{ minWidth: '170px' }}
|
|
95
|
+
onClick={(e) => {
|
|
96
|
+
if (item.closableOnClick !== false) PopoverGlobal.Api.close()
|
|
97
|
+
item.onClick && item.onClick(e, this.props.value)
|
|
98
|
+
}}
|
|
99
|
+
{...item.listItemProps}
|
|
100
|
+
>
|
|
101
|
+
<ListItemButton>
|
|
102
|
+
<ListItemIcon>{item.icon}</ListItemIcon>
|
|
103
|
+
<ListItemText primary={item.name} />
|
|
104
|
+
</ListItemButton>
|
|
105
|
+
</ListItem>
|
|
106
|
+
)
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
renderItemWithForm = (name: TableGridItemActionType, form?: FormRenderFunc<T>, globalState?: GlobalModalState) => {
|
|
111
|
+
if (!form) return <></>
|
|
112
|
+
return MapGlobalModalContext((context) => (
|
|
113
|
+
<ListItem
|
|
114
|
+
disablePadding
|
|
115
|
+
sx={{ minWidth: '170px' }}
|
|
116
|
+
onClick={() => {
|
|
117
|
+
PopoverGlobal.Api.close()
|
|
118
|
+
context.show({ renderContent: () => form(this.props.value), ...globalState })
|
|
119
|
+
}}
|
|
120
|
+
>
|
|
121
|
+
<ListItemButton>
|
|
122
|
+
<ListItemIcon>{mapIcons[name]}</ListItemIcon>
|
|
123
|
+
<ListItemText primary={name} />
|
|
124
|
+
</ListItemButton>
|
|
125
|
+
</ListItem>
|
|
126
|
+
))
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return TableGridItemActions
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const Wrap = styled(Box)({
|
|
133
|
+
background: colors.common.white,
|
|
134
|
+
borderRadius: '6px',
|
|
135
|
+
'& > .MuiButtonBase-root': {
|
|
136
|
+
borderRadius: '6px'
|
|
137
|
+
}
|
|
138
|
+
})
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import React, { Component } from 'react'
|
|
2
|
+
import { Box, BoxProps, Button, ButtonProps, styled, Tooltip, Typography, TypographyProps } from '@mui/material'
|
|
3
|
+
import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline'
|
|
4
|
+
import { MapGlobalModalContext } from '../../api-context'
|
|
5
|
+
import CustomBreadcrumbs, { CustomBreadcrumbConfig } from '../../components/custom.breadcrumbs'
|
|
6
|
+
|
|
7
|
+
interface SectionSlots {
|
|
8
|
+
before?: React.ReactNode
|
|
9
|
+
after?: React.ReactNode
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ToolbarPannelProps {
|
|
13
|
+
/** @default true */
|
|
14
|
+
visible?: boolean
|
|
15
|
+
searchInclude?: string[]
|
|
16
|
+
breadcrumbs?: CustomBreadcrumbConfig[]
|
|
17
|
+
title?: React.ReactNode
|
|
18
|
+
titleSlots?: SectionSlots
|
|
19
|
+
formCreate?: React.ReactNode
|
|
20
|
+
actionSlots?: SectionSlots
|
|
21
|
+
slots?: {
|
|
22
|
+
rootProps?: BoxProps
|
|
23
|
+
buttonCreateProps?: ButtonProps
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
class ToolbarPannel extends Component<ToolbarPannelProps> {
|
|
28
|
+
render() {
|
|
29
|
+
if (this.props.visible === false) return
|
|
30
|
+
return (
|
|
31
|
+
<Wrap {...this.props.slots?.rootProps}>
|
|
32
|
+
{this.props.titleSlots?.before}
|
|
33
|
+
{this.renderTitle()}
|
|
34
|
+
{this.props.titleSlots?.after}
|
|
35
|
+
<Box sx={{ flex: 1 }} />
|
|
36
|
+
{this.props.actionSlots?.before}
|
|
37
|
+
{this.renderButtonCreate()}
|
|
38
|
+
{this.props.actionSlots?.after}
|
|
39
|
+
</Wrap>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
renderButtonCreate = () => {
|
|
44
|
+
if (!this.props.formCreate) return <></>
|
|
45
|
+
return MapGlobalModalContext((context) => (
|
|
46
|
+
<Tooltip title='Create new'>
|
|
47
|
+
<Button
|
|
48
|
+
size='small'
|
|
49
|
+
onClick={() => context.show({ renderContent: () => this.props.formCreate })}
|
|
50
|
+
startIcon={<AddCircleOutlineIcon fontSize='small' />}
|
|
51
|
+
sx={{ fontWeight: 600 }}
|
|
52
|
+
variant='contained'
|
|
53
|
+
{...this.props.slots?.buttonCreateProps}
|
|
54
|
+
>
|
|
55
|
+
Create
|
|
56
|
+
</Button>
|
|
57
|
+
</Tooltip>
|
|
58
|
+
))
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
renderTitle = () => {
|
|
62
|
+
const { title, breadcrumbs } = this.props ?? {}
|
|
63
|
+
if (breadcrumbs) return <CustomBreadcrumbs value={breadcrumbs} />
|
|
64
|
+
if (typeof title === 'string') return <Title>{title}</Title>
|
|
65
|
+
return <>{title}</>
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export default ToolbarPannel
|
|
70
|
+
|
|
71
|
+
// const SeachHelp = styled('ul')({
|
|
72
|
+
// margin: '0 0 0 18px',
|
|
73
|
+
// padding: 0,
|
|
74
|
+
// li: {
|
|
75
|
+
// position: 'relative'
|
|
76
|
+
// },
|
|
77
|
+
// 'li::after': {
|
|
78
|
+
// content: '"►"',
|
|
79
|
+
// display: 'inline-block',
|
|
80
|
+
// top: '50%',
|
|
81
|
+
// transform: 'translateY(-50%)',
|
|
82
|
+
// position: 'absolute',
|
|
83
|
+
// left: '-18px'
|
|
84
|
+
// }
|
|
85
|
+
// })
|
|
86
|
+
|
|
87
|
+
const Title = styled((props: TypographyProps) => <Typography noWrap variant='subtitle1' {...props} />)({
|
|
88
|
+
fontWeight: 700,
|
|
89
|
+
flex: 1
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
const Wrap = styled(Box)({
|
|
93
|
+
height: 'var(--height-toolbar, 56px)',
|
|
94
|
+
display: 'flex',
|
|
95
|
+
alignItems: 'center',
|
|
96
|
+
gap: '8px',
|
|
97
|
+
padding: '0 6px'
|
|
98
|
+
})
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { ComponentType, ReactNode } from 'react'
|
|
2
|
+
import { GridProps, RegularBreakpoints } from '@mui/material'
|
|
3
|
+
import { FilterBarParams, FilterState } from '../filter-bar'
|
|
4
|
+
import { ToolbarPannelProps } from './toolbar-pannel'
|
|
5
|
+
import { TableGridItemActionsConfig, TableGridItemActionsProps } from './item-actions'
|
|
6
|
+
|
|
7
|
+
export interface TableGridItemProps<T = any> {
|
|
8
|
+
value: T
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type GetSelecterIdFunc<T> = (item: T) => string
|
|
12
|
+
|
|
13
|
+
export interface PaginationModel {
|
|
14
|
+
page: number
|
|
15
|
+
pageSize: number
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface TableGridFilter<T> extends FilterState<T> {
|
|
19
|
+
pagination: PaginationModel
|
|
20
|
+
loading?: boolean
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface TableGridFlexibleSlots<T> {
|
|
24
|
+
item?: ComponentType<TableGridItemProps<T>>
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface TableGridSlots<T> extends TableGridFlexibleSlots<T> {
|
|
28
|
+
flex?: boolean
|
|
29
|
+
gridContainer?: GridProps
|
|
30
|
+
gridItem?: GridProps
|
|
31
|
+
toolbar?: ComponentType
|
|
32
|
+
toolbarProps?: ToolbarPannelProps
|
|
33
|
+
action?: ComponentType<TableGridItemActionsProps<T>>
|
|
34
|
+
actionProps?: TableGridItemActionsConfig<T>
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface TableGridInnerSlots<T> extends TableGridSlots<T> {
|
|
38
|
+
TableGridItem: ComponentType<TableGridItemProps<T>>
|
|
39
|
+
ToolbarPannel: ComponentType<ToolbarPannelProps>
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface TableGridParams<T> extends TableGridFlexibleSlots<T> {
|
|
43
|
+
getSelecterId: GetSelecterIdFunc<T>
|
|
44
|
+
title?: ReactNode
|
|
45
|
+
filterBarConfig?: FilterBarParams<T>
|
|
46
|
+
size?: RegularBreakpoints
|
|
47
|
+
slots?: TableGridSlots<T>
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface TableGridData<T> {
|
|
51
|
+
items?: T[]
|
|
52
|
+
totalItems?: number
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface TableGridProps<T> {
|
|
56
|
+
data: TableGridData<T>
|
|
57
|
+
filter?: TableGridFilter<T>
|
|
58
|
+
onFilterChange?: (value: TableGridFilter<T>) => void
|
|
59
|
+
slots?: TableGridSlots<T>
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface TableGridReduxState<T> {
|
|
63
|
+
tableData: TableGridData<T>
|
|
64
|
+
tableFilter: TableGridFilter<T>
|
|
65
|
+
tableFilterThunk: TableGridFilter<T>
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export type TableGridStateRedux<T, K extends keyof TableGridReduxState<T> = keyof TableGridReduxState<T>> = Pick<TableGridReduxState<T>, K>
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import React, { Component, PropsWithChildren } from 'react'
|
|
2
|
+
import { IErrorViewDefaultProps, IHocLazyWrapperProps } from './ui.units'
|
|
3
|
+
import { ELazyStatus, DinoReduxDispatch, DinoReduxState, ReturnDispatch } from './types'
|
|
4
|
+
import UIErrorPage from './ui.error-page'
|
|
5
|
+
|
|
6
|
+
interface IHocLazyBase<TModel> extends DinoReduxState, DinoReduxDispatch<TModel> {}
|
|
7
|
+
|
|
8
|
+
export interface IOptionBase {
|
|
9
|
+
ErrorScreen?: React.ComponentType<IErrorViewDefaultProps>
|
|
10
|
+
LazySpinner: React.ComponentType<PropsWithChildren<IHocLazyWrapperProps>>
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface IHocLazyOtherProps<TModel> {
|
|
14
|
+
param?: TModel
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface IHocLazyOptions<TModel> extends IHocLazyOtherProps<TModel>, Omit<IOptionBase, 'LazySpinner'> {
|
|
18
|
+
LazySpinner?: React.ComponentType<PropsWithChildren<IHocLazyWrapperProps>>
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const EmptyComponent: React.FC<React.PropsWithChildren<any>> = ({ children }) => <>{children}</>
|
|
22
|
+
|
|
23
|
+
export const OptionHocLazyDefault: IOptionBase = {
|
|
24
|
+
LazySpinner: EmptyComponent
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const CreateHocLazy = function <TChildProp extends IHocLazyBase<TModel>, TModel = any>(
|
|
28
|
+
ChildComponent: React.ComponentType<TChildProp>,
|
|
29
|
+
options?: IHocLazyOptions<TModel>
|
|
30
|
+
) {
|
|
31
|
+
type TProps = TChildProp & IHocLazyOtherProps<TModel>
|
|
32
|
+
class HocComponent extends Component<TProps> {
|
|
33
|
+
optionsMerge: IOptionBase
|
|
34
|
+
tokenSources?: AbortController
|
|
35
|
+
fetchSource?: ReturnDispatch
|
|
36
|
+
constructor(props: TProps) {
|
|
37
|
+
super(props)
|
|
38
|
+
this.optionsMerge = Object.assign({}, OptionHocLazyDefault, options) as IOptionBase
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
render() {
|
|
42
|
+
const { optionsMerge: OptionsMerge } = this
|
|
43
|
+
switch (this.props.status) {
|
|
44
|
+
case ELazyStatus.Loading:
|
|
45
|
+
case ELazyStatus.Loaded:
|
|
46
|
+
return (
|
|
47
|
+
<OptionsMerge.LazySpinner loading={this.props.status === ELazyStatus.Loading}>
|
|
48
|
+
<ChildComponent {...this.props} />
|
|
49
|
+
</OptionsMerge.LazySpinner>
|
|
50
|
+
)
|
|
51
|
+
case ELazyStatus.Error:
|
|
52
|
+
return <UIErrorPage />
|
|
53
|
+
default:
|
|
54
|
+
return <div></div>
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
initialParam = (): TModel => {
|
|
59
|
+
const oData = options?.param ?? {}
|
|
60
|
+
const pData = this.props?.param ?? {}
|
|
61
|
+
return Object.assign({}, oData, pData) as TModel
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
componentDidMount = () => {
|
|
65
|
+
if (this.props.fetchData) {
|
|
66
|
+
const param = this.initialParam()
|
|
67
|
+
this.tokenSources?.abort()
|
|
68
|
+
this.tokenSources = new AbortController()
|
|
69
|
+
this.fetchSource = this.props.fetchData(param, this.tokenSources.signal)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
componentWillUnmount() {
|
|
74
|
+
this.tokenSources?.abort()
|
|
75
|
+
this.fetchSource?.abort && this.fetchSource.abort()
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return HocComponent
|
|
79
|
+
}
|
|
80
|
+
export default CreateHocLazy
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export enum ELazyStatus {
|
|
2
|
+
Loading = 'Loading',
|
|
3
|
+
Loaded = 'Loaded',
|
|
4
|
+
Error = 'Error'
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface DinoReduxState {
|
|
8
|
+
status: ELazyStatus
|
|
9
|
+
requestedId?: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ReturnDispatch {
|
|
13
|
+
abort?: () => void
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface DinoReduxDispatch<P = any> {
|
|
17
|
+
fetchData?: (params?: P, signal?: AbortSignal) => ReturnDispatch
|
|
18
|
+
setStatus: (status: ELazyStatus) => void
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface Actions<T, Id extends keyof T> {
|
|
22
|
+
create: (value: Partial<T>, signal?: AbortSignal) => Promise<void>
|
|
23
|
+
update: (id: T[Id], value: Partial<T>, signal?: AbortSignal) => Promise<void>
|
|
24
|
+
delete: (id: T[Id], value?: Partial<T>, signal?: AbortSignal) => Promise<void>
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type DinoReduxActions<T, Id extends keyof T, K extends keyof Actions<T, Id> = keyof Actions<T, Id>> = Pick<Actions<T, Id>, K>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import React, { FC } from 'react'
|
|
2
|
+
import { Box, BoxProps, Button, ButtonProps, Stack, styled, Typography } from '@mui/material'
|
|
3
|
+
import ArrowRightAltIcon from '@mui/icons-material/ArrowRightAlt'
|
|
4
|
+
import Error404Vector from './vector-404.webp'
|
|
5
|
+
|
|
6
|
+
const UIErrorPage: FC = () => (
|
|
7
|
+
<Stack sx={{ alignItems: 'center' }}>
|
|
8
|
+
<WrapImage>
|
|
9
|
+
<img src={Error404Vector} alt='error-404-vector' />
|
|
10
|
+
</WrapImage>
|
|
11
|
+
<Typography variant='subtitle1' component='p' sx={{ textAlign: 'center', mt: '20px' }}>
|
|
12
|
+
Sorry, page not found or connection to server lost. Please come back later....
|
|
13
|
+
</Typography>
|
|
14
|
+
<CustomButton href='/'>Back to home page</CustomButton>
|
|
15
|
+
</Stack>
|
|
16
|
+
)
|
|
17
|
+
export default UIErrorPage
|
|
18
|
+
|
|
19
|
+
const WrapImage = styled(({ children, ...props }: BoxProps) => (
|
|
20
|
+
<Box {...props}>
|
|
21
|
+
<div>{children}</div>
|
|
22
|
+
</Box>
|
|
23
|
+
))({
|
|
24
|
+
width: '100%',
|
|
25
|
+
maxWidth: '560px',
|
|
26
|
+
flex: '0 0 auto',
|
|
27
|
+
'& > div': {
|
|
28
|
+
width: '100%',
|
|
29
|
+
paddingBottom: '100%',
|
|
30
|
+
position: 'relative'
|
|
31
|
+
},
|
|
32
|
+
'& img': {
|
|
33
|
+
position: 'absolute',
|
|
34
|
+
top: 0,
|
|
35
|
+
left: 0,
|
|
36
|
+
width: '100%',
|
|
37
|
+
height: '100%'
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
const CustomButton = styled((p: ButtonProps & { href: string }) => {
|
|
42
|
+
return <Button component='a' color='inherit' variant='contained' size='large' endIcon={<ArrowRightAltIcon fontSize='small' />} {...p} />
|
|
43
|
+
})({
|
|
44
|
+
backgroundColor: 'var(--color-black)',
|
|
45
|
+
color: 'var(--color-text-light)',
|
|
46
|
+
minWidth: '250px',
|
|
47
|
+
marginTop: '24px',
|
|
48
|
+
height: '56px',
|
|
49
|
+
textTransform: 'none',
|
|
50
|
+
fontWeight: 600,
|
|
51
|
+
transition: '0.3s',
|
|
52
|
+
'&:hover': {
|
|
53
|
+
backgroundColor: 'var(--color-black2)',
|
|
54
|
+
color: 'var(--color-text-light)'
|
|
55
|
+
},
|
|
56
|
+
'& .MuiButton-icon.MuiButton-endIcon': {
|
|
57
|
+
transition: '0.3s'
|
|
58
|
+
},
|
|
59
|
+
'&:hover .MuiButton-icon.MuiButton-endIcon': {
|
|
60
|
+
marginLeft: '16px'
|
|
61
|
+
}
|
|
62
|
+
})
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React, { FC, PropsWithChildren } from 'react'
|
|
2
|
+
import { Box, Button, Fade, Stack, styled, Typography } from '@mui/material'
|
|
3
|
+
|
|
4
|
+
export interface IErrorViewDefaultProps {}
|
|
5
|
+
|
|
6
|
+
export const ErrorViewDefault: FC<IErrorViewDefaultProps> = () => (
|
|
7
|
+
<Stack sx={{ height: '100vh', alignItems: 'center', justifyContent: 'center' }}>
|
|
8
|
+
<Typography variant='h1'>Errors Something</Typography>
|
|
9
|
+
<Typography variant='subtitle1'>Please try again :{'(('}</Typography>
|
|
10
|
+
<Button variant='outlined' color='inherit' LinkComponent='a' href='/'>
|
|
11
|
+
Try again
|
|
12
|
+
</Button>
|
|
13
|
+
</Stack>
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
export interface IHocLazyWrapperProps extends PropsWithChildren {
|
|
17
|
+
loading?: boolean
|
|
18
|
+
backdrop?: boolean
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const HocLazyWrapper: FC<IHocLazyWrapperProps> = (props) => (
|
|
22
|
+
<React.Fragment>
|
|
23
|
+
{props.children}
|
|
24
|
+
<Fade in={props.loading === true && props.backdrop !== false} unmountOnExit>
|
|
25
|
+
<Wrapper />
|
|
26
|
+
</Fade>
|
|
27
|
+
</React.Fragment>
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
const Wrapper = styled(Box)({
|
|
31
|
+
top: 0,
|
|
32
|
+
left: 0,
|
|
33
|
+
width: '100%',
|
|
34
|
+
height: '100%',
|
|
35
|
+
position: 'fixed',
|
|
36
|
+
background: 'rgb(0,0,0,0.15)',
|
|
37
|
+
display: 'flex',
|
|
38
|
+
justifyContent: 'center',
|
|
39
|
+
alignItems: 'center',
|
|
40
|
+
zIndex: 1150
|
|
41
|
+
})
|
|
Binary file
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React, { createContext } from 'react'
|
|
2
|
+
import { TCloseModal, TShowModal } from '../api-context'
|
|
3
|
+
|
|
4
|
+
export interface ITableBaseContext {
|
|
5
|
+
showModal: TShowModal
|
|
6
|
+
closeModal: TCloseModal
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const TableBaseContext = createContext<ITableBaseContext>({
|
|
10
|
+
showModal: () => {},
|
|
11
|
+
closeModal: () => {}
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
export const MapTableBaseContext = (context: (context: ITableBaseContext) => React.ReactNode) => (
|
|
15
|
+
<TableBaseContext.Consumer>{context}</TableBaseContext.Consumer>
|
|
16
|
+
)
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import React, { Component } from 'react'
|
|
2
|
+
import { Box, BoxProps, IconButton, Tooltip } from '@mui/material'
|
|
3
|
+
import EditIcon from '@mui/icons-material/Edit'
|
|
4
|
+
import DeleteIcon from '@mui/icons-material/Delete'
|
|
5
|
+
import { GlobalModalState } from '../api-context'
|
|
6
|
+
import { ITableBaseContext, MapTableBaseContext } from './context'
|
|
7
|
+
import { mergeObjects } from '../utils'
|
|
8
|
+
|
|
9
|
+
export interface IActionRowProps<T> {
|
|
10
|
+
value: T
|
|
11
|
+
formEdit?: (value: T, tableContext: ITableBaseContext) => React.ReactNode
|
|
12
|
+
formDelete?: (value: T, tableContext: ITableBaseContext) => React.ReactNode
|
|
13
|
+
after?: (value: T, tableContext: ITableBaseContext) => React.ReactNode
|
|
14
|
+
before?: (value: T, tableContext: ITableBaseContext) => React.ReactNode
|
|
15
|
+
wrapProps?: BoxProps
|
|
16
|
+
buttonEditConfig?: GlobalModalState
|
|
17
|
+
buttonDeleteConfig?: GlobalModalState
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function CreateActionRow<T>(params?: Omit<IActionRowProps<T>, 'value'>) {
|
|
21
|
+
class ActionRow extends Component<IActionRowProps<T>> {
|
|
22
|
+
get propsMerge() {
|
|
23
|
+
return mergeObjects<IActionRowProps<T>>(params, this.props)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
getButtons = function* (that: ActionRow, thatProps: Omit<IActionRowProps<T>, 'value'>, tableContext: ITableBaseContext) {
|
|
27
|
+
const beforeFunc = that.props?.before ?? thatProps?.before
|
|
28
|
+
if (beforeFunc) {
|
|
29
|
+
yield <React.Fragment key='Before'>{beforeFunc(that.props.value, tableContext)}</React.Fragment>
|
|
30
|
+
}
|
|
31
|
+
const editFunc = that.props?.formEdit ?? thatProps?.formEdit
|
|
32
|
+
const editContent = editFunc ? editFunc(that.props.value, tableContext) : undefined
|
|
33
|
+
if (editFunc && !!editContent) {
|
|
34
|
+
yield (
|
|
35
|
+
<Tooltip title='Edit' arrow key='Edit'>
|
|
36
|
+
<IconButton
|
|
37
|
+
color='primary'
|
|
38
|
+
onClick={() => {
|
|
39
|
+
tableContext?.showModal({
|
|
40
|
+
renderContent: () => editContent || <React.Fragment />,
|
|
41
|
+
sx: { display: 'flex', justifyContent: 'center', alignItems: 'center' },
|
|
42
|
+
backdropActivated: true,
|
|
43
|
+
...params?.buttonEditConfig
|
|
44
|
+
})
|
|
45
|
+
}}
|
|
46
|
+
>
|
|
47
|
+
<EditIcon fontSize='small' />
|
|
48
|
+
</IconButton>
|
|
49
|
+
</Tooltip>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
const deleteFunc = that.props?.formDelete ?? thatProps?.formDelete
|
|
53
|
+
const deleteContent = deleteFunc ? deleteFunc(that.props.value, tableContext) : undefined
|
|
54
|
+
if (deleteFunc && !!deleteContent) {
|
|
55
|
+
yield (
|
|
56
|
+
<Tooltip title='Delete' arrow key='Delete'>
|
|
57
|
+
<IconButton
|
|
58
|
+
color='error'
|
|
59
|
+
onClick={() => {
|
|
60
|
+
tableContext?.showModal({
|
|
61
|
+
renderContent: () => deleteContent || <React.Fragment />,
|
|
62
|
+
sx: { display: 'flex', justifyContent: 'center', alignItems: 'center' },
|
|
63
|
+
backdropActivated: true,
|
|
64
|
+
...params?.buttonDeleteConfig
|
|
65
|
+
})
|
|
66
|
+
}}
|
|
67
|
+
>
|
|
68
|
+
<DeleteIcon fontSize='small' />
|
|
69
|
+
</IconButton>
|
|
70
|
+
</Tooltip>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
const afterFunc = that.props?.after ?? thatProps?.after
|
|
74
|
+
if (afterFunc) {
|
|
75
|
+
yield <React.Fragment key='After'>{afterFunc(that.props.value, tableContext)}</React.Fragment>
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
render() {
|
|
80
|
+
return MapTableBaseContext((context) => (
|
|
81
|
+
<Box sx={{ display: 'flex', alignItems: 'center', height: '100%' }} {...this.propsMerge.wrapProps}>
|
|
82
|
+
{Array.from(this.getButtons(this, this.propsMerge, context))}
|
|
83
|
+
</Box>
|
|
84
|
+
))
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return ActionRow
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export default CreateActionRow
|