@dartech/arsenal-ui 0.0.1
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/.babelrc +12 -0
- package/.eslintrc.json +22 -0
- package/README.md +7 -0
- package/index.ts +3 -0
- package/jest.config.js +9 -0
- package/package.json +21 -0
- package/project.json +69 -0
- package/rollup.config.js +135 -0
- package/src/interfaces/common.ts +12 -0
- package/src/interfaces/definition.ts +143 -0
- package/src/interfaces/index.ts +3 -0
- package/src/interfaces/ui.ts +35 -0
- package/src/lib/Alert/Alert.tsx +108 -0
- package/src/lib/Alert/index.ts +1 -0
- package/src/lib/Definition/CreateDefinition/CreateDefinition.tsx +74 -0
- package/src/lib/Definition/CreateDefinition/index.ts +1 -0
- package/src/lib/Definition/DefinitionFiller/DefinitionFiller.tsx +85 -0
- package/src/lib/Definition/DefinitionFiller/WidgetDefinitionFiller.tsx +96 -0
- package/src/lib/Definition/DefinitionFiller/index.ts +2 -0
- package/src/lib/Definition/index.ts +2 -0
- package/src/lib/DemPropertyField/DemPropertyField.tsx +93 -0
- package/src/lib/DemPropertyField/DemPropertyView/DemPropertyView.tsx +44 -0
- package/src/lib/DemPropertyField/DemPropertyView/index.ts +1 -0
- package/src/lib/DemPropertyField/MultipleDemField/MultipleDemField.tsx +293 -0
- package/src/lib/DemPropertyField/MultipleDemField/index.tsx +1 -0
- package/src/lib/DemPropertyField/RestrictedValuesEditor.tsx +63 -0
- package/src/lib/DemPropertyField/SingleDemField/SingleDemField.tsx +156 -0
- package/src/lib/DemPropertyField/SingleDemField/index.ts +1 -0
- package/src/lib/DemPropertyField/index.ts +2 -0
- package/src/lib/DemPropertyField/styles.ts +50 -0
- package/src/lib/DemPropertyField/widgets/DemBooleanWidget.tsx +26 -0
- package/src/lib/DemPropertyField/widgets/DemDateTimeWidget.tsx +34 -0
- package/src/lib/DemPropertyField/widgets/DemDateWidget.tsx +33 -0
- package/src/lib/DemPropertyField/widgets/DemFieldWidget.tsx +67 -0
- package/src/lib/DemPropertyField/widgets/DemFloatWidget.tsx +49 -0
- package/src/lib/DemPropertyField/widgets/DemIntegerWidget.tsx +63 -0
- package/src/lib/DemPropertyField/widgets/DemJsonWidget.tsx +33 -0
- package/src/lib/DemPropertyField/widgets/DemStringWidget.tsx +35 -0
- package/src/lib/DemPropertyField/widgets/DemTimeWidget.tsx +46 -0
- package/src/lib/DemPropertyField/widgets/index.ts +1 -0
- package/src/lib/Forms/BackButton.tsx +45 -0
- package/src/lib/Forms/ControlAceEditor.tsx +103 -0
- package/src/lib/Forms/ControlAutocomplete.tsx +134 -0
- package/src/lib/Forms/ControlCheckbox.tsx +57 -0
- package/src/lib/Forms/ControlDebouncedInput.tsx +69 -0
- package/src/lib/Forms/ControlInput.tsx +102 -0
- package/src/lib/Forms/ControlNumberInput.tsx +144 -0
- package/src/lib/Forms/ControlRadioBtn.tsx +46 -0
- package/src/lib/Forms/ControlSelect.tsx +135 -0
- package/src/lib/Forms/CopyButton.tsx +49 -0
- package/src/lib/Forms/index.ts +10 -0
- package/src/lib/InfoItem/InfoItem.tsx +39 -0
- package/src/lib/InfoItem/index.ts +1 -0
- package/src/lib/InfoItem/styles.ts +17 -0
- package/src/lib/JsonPathPicker/JsonPathPicker.tsx +71 -0
- package/src/lib/JsonPathPicker/PropertyStep.tsx +74 -0
- package/src/lib/JsonPathPicker/index.ts +1 -0
- package/src/lib/JsonView/JsonView.tsx +43 -0
- package/src/lib/JsonView/index.ts +1 -0
- package/src/lib/Loader/Loader.tsx +41 -0
- package/src/lib/Loader/index.ts +1 -0
- package/src/lib/Modals/JsonModalView.tsx +52 -0
- package/src/lib/Modals/index.ts +1 -0
- package/src/lib/Property/PropertyValueField/BooleanValueField.tsx +41 -0
- package/src/lib/Property/PropertyValueField/DateTimeValueField.tsx +59 -0
- package/src/lib/Property/PropertyValueField/DateValueField.tsx +59 -0
- package/src/lib/Property/PropertyValueField/EntityValueField.tsx +33 -0
- package/src/lib/Property/PropertyValueField/JsonValueField.tsx +64 -0
- package/src/lib/Property/PropertyValueField/PropertyValue.tsx +97 -0
- package/src/lib/Property/PropertyValueField/PropertyValueField.tsx +86 -0
- package/src/lib/Property/PropertyValueField/StringValueField.tsx +21 -0
- package/src/lib/Property/PropertyValueField/TimeValueField.tsx +68 -0
- package/src/lib/Property/PropertyValueField/ValueComponent.tsx +63 -0
- package/src/lib/Property/PropertyValueField/index.ts +1 -0
- package/src/lib/Property/PropertyWidget/PropertyWidget.tsx +167 -0
- package/src/lib/Property/PropertyWidget/index.ts +1 -0
- package/src/lib/Property/UpsertProperty/CreatePropertiesList.tsx +131 -0
- package/src/lib/Property/UpsertProperty/CreatePropertyFormFields.tsx +147 -0
- package/src/lib/Property/UpsertProperty/CustomPropertyField.tsx +40 -0
- package/src/lib/Property/UpsertProperty/PropertyAdditionalFields/BigDecimalPropertyFields.tsx +41 -0
- package/src/lib/Property/UpsertProperty/PropertyAdditionalFields/DateAdditionalFields.tsx +27 -0
- package/src/lib/Property/UpsertProperty/PropertyAdditionalFields/EntityAdditionalFields.tsx +133 -0
- package/src/lib/Property/UpsertProperty/PropertyAdditionalFields/EntityReferencePropertyFields.tsx +46 -0
- package/src/lib/Property/UpsertProperty/PropertyAdditionalFields/PropertyAdditionalFields.tsx +52 -0
- package/src/lib/Property/UpsertProperty/PropertyAdditionalFields/StringPropertyFields.tsx +98 -0
- package/src/lib/Property/UpsertProperty/PropertyAdditionalFields/index.ts +1 -0
- package/src/lib/Property/UpsertProperty/index.ts +2 -0
- package/src/lib/Property/UpsertProperty/useCustomFields.ts +22 -0
- package/src/lib/Property/ViewPropertiesList/ViewPropertiesList.tsx +50 -0
- package/src/lib/Property/ViewPropertiesList/index.ts +1 -0
- package/src/lib/Property/ViewProperty/EntityPropertiesShortView.tsx +41 -0
- package/src/lib/Property/ViewProperty/EntityPropertiesView.tsx +48 -0
- package/src/lib/Property/ViewProperty/PropertyDataTable.tsx +139 -0
- package/src/lib/Property/ViewProperty/PropertyItem.tsx +46 -0
- package/src/lib/Property/ViewProperty/ViewProperty.tsx +52 -0
- package/src/lib/Property/ViewProperty/index.ts +1 -0
- package/src/lib/Property/index.ts +4 -0
- package/src/lib/Status/Status.tsx +15 -0
- package/src/lib/Status/index.ts +1 -0
- package/src/lib/Status/styles.ts +14 -0
- package/src/lib/Table/Table.tsx +116 -0
- package/src/lib/Table/TableColumnMenu.tsx +12 -0
- package/src/lib/Table/TablePagination.tsx +42 -0
- package/src/lib/Table/index.ts +1 -0
- package/src/lib/Table/styles.ts +59 -0
- package/src/lib/Table/usePagination.ts +15 -0
- package/src/lib/Table/useTableQueryPagination.ts +49 -0
- package/src/lib/Table/useTableQuerySorting.ts +52 -0
- package/src/lib/Tabs/RouteTabs.tsx +54 -0
- package/src/lib/Tabs/TabPanel.tsx +42 -0
- package/src/lib/Tabs/index.ts +2 -0
- package/src/lib/TemplateContent/ExpressionDecorator.tsx +7 -0
- package/src/lib/TemplateContent/TemplateContentEditor.tsx +144 -0
- package/src/lib/TemplateContent/index.ts +1 -0
- package/src/lib/index.ts +14 -0
- package/src/utils/common.ts +68 -0
- package/src/utils/dem.ts +78 -0
- package/src/utils/hooks.ts +41 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/ui-utils.tsx +71 -0
- package/src/utils/validators.ts +130 -0
- package/tsconfig.json +24 -0
- package/tsconfig.lib.json +22 -0
- package/tsconfig.spec.json +19 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import Box from '@material-ui/core/Box';
|
3
|
+
import Pagination from '@material-ui/lab/Pagination';
|
4
|
+
import MuiTablePagination from '@material-ui/core/TablePagination';
|
5
|
+
import {
|
6
|
+
gridPageCountSelector,
|
7
|
+
gridPageSelector,
|
8
|
+
gridRowCountSelector,
|
9
|
+
gridPageSizeSelector,
|
10
|
+
useGridApiContext,
|
11
|
+
useGridSelector,
|
12
|
+
} from '@mui/x-data-grid';
|
13
|
+
|
14
|
+
const TablePagination = () => {
|
15
|
+
const apiRef = useGridApiContext();
|
16
|
+
const page = useGridSelector(apiRef, gridPageSelector);
|
17
|
+
const pageCount = useGridSelector(apiRef, gridPageCountSelector);
|
18
|
+
const rowCount = useGridSelector(apiRef, gridRowCountSelector);
|
19
|
+
const pageSize = useGridSelector(apiRef, gridPageSizeSelector);
|
20
|
+
|
21
|
+
const onPageChange = (value) => apiRef.current.setPage(value);
|
22
|
+
const onRowsPerPageChange = (event: React.ChangeEvent<HTMLInputElement>) =>
|
23
|
+
apiRef.current.setPageSize(parseInt(event.target.value, 10));
|
24
|
+
|
25
|
+
return (
|
26
|
+
<Box px={2} display="flex" alignItems="center">
|
27
|
+
<MuiTablePagination
|
28
|
+
component="div"
|
29
|
+
page={page}
|
30
|
+
count={rowCount}
|
31
|
+
rowsPerPage={pageSize}
|
32
|
+
rowsPerPageOptions={[10, 20, 50, 100]}
|
33
|
+
onPageChange={(event, value) => onPageChange(value)}
|
34
|
+
onRowsPerPageChange={onRowsPerPageChange}
|
35
|
+
ActionsComponent={() => <></>}
|
36
|
+
/>
|
37
|
+
<Pagination count={pageCount} page={page + 1} onChange={(event, value) => onPageChange(value - 1)} />
|
38
|
+
</Box>
|
39
|
+
);
|
40
|
+
};
|
41
|
+
|
42
|
+
export default TablePagination;
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from './Table';
|
@@ -0,0 +1,59 @@
|
|
1
|
+
import { makeStyles } from '@material-ui/core/styles';
|
2
|
+
|
3
|
+
export default makeStyles({
|
4
|
+
root: {
|
5
|
+
width: '100%',
|
6
|
+
|
7
|
+
'& .MuiDataGrid-virtualScrollerContent': {
|
8
|
+
height: 'auto !important',
|
9
|
+
minHeight: '56px !important',
|
10
|
+
},
|
11
|
+
|
12
|
+
'& .MuiDataGrid-virtualScrollerRenderZone': {
|
13
|
+
position: 'static',
|
14
|
+
},
|
15
|
+
|
16
|
+
'& .MuiDataGrid-renderingZone': {
|
17
|
+
maxHeight: 'none !important',
|
18
|
+
},
|
19
|
+
|
20
|
+
'& .MuiDataGrid-cell': {
|
21
|
+
maxHeight: 'none !important',
|
22
|
+
lineHeight: 'unset !important',
|
23
|
+
whiteSpace: 'normal !important',
|
24
|
+
textOverflow: 'ellipsis',
|
25
|
+
wordBreak: 'break-all',
|
26
|
+
|
27
|
+
'& .MuiDataGrid-actionsCell': {
|
28
|
+
width: '100%',
|
29
|
+
gridGap: '4px',
|
30
|
+
flexWrap: 'wrap',
|
31
|
+
|
32
|
+
'& > button[aria-label="more"]': {
|
33
|
+
marginLeft: 'auto',
|
34
|
+
},
|
35
|
+
},
|
36
|
+
},
|
37
|
+
|
38
|
+
'& .MuiDataGrid-row': {
|
39
|
+
maxHeight: 'none !important',
|
40
|
+
},
|
41
|
+
|
42
|
+
'& .Sorted': {
|
43
|
+
'& .MuiDataGrid-iconButtonContainer': {
|
44
|
+
visibility: 'visible',
|
45
|
+
width: 'auto',
|
46
|
+
|
47
|
+
'& svg': {
|
48
|
+
opacity: '1 !important',
|
49
|
+
},
|
50
|
+
},
|
51
|
+
|
52
|
+
'&.--desc': {
|
53
|
+
'& svg': {
|
54
|
+
transform: 'rotate(180deg)',
|
55
|
+
},
|
56
|
+
},
|
57
|
+
},
|
58
|
+
},
|
59
|
+
});
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import { useEffect, useState } from 'react';
|
2
|
+
|
3
|
+
const usePagination = (initialPageSize?: number) => {
|
4
|
+
const [pageSize, setPageSize] = useState(10);
|
5
|
+
|
6
|
+
useEffect(() => {
|
7
|
+
setPageSize(initialPageSize);
|
8
|
+
}, [initialPageSize]);
|
9
|
+
|
10
|
+
const handlePageSizeChange = (size) => setPageSize(size);
|
11
|
+
|
12
|
+
return { pageSize, handlePageSizeChange };
|
13
|
+
};
|
14
|
+
|
15
|
+
export default usePagination;
|
@@ -0,0 +1,49 @@
|
|
1
|
+
import { useEffect, useMemo } from 'react';
|
2
|
+
import { useLocation, useHistory } from 'react-router-dom';
|
3
|
+
import { GridFeatureMode } from '@mui/x-data-grid';
|
4
|
+
|
5
|
+
interface Props {
|
6
|
+
mode: GridFeatureMode;
|
7
|
+
}
|
8
|
+
|
9
|
+
export const useTableQueryPagination = ({ mode }: Props) => {
|
10
|
+
const history = useHistory();
|
11
|
+
const { search, state } = useLocation();
|
12
|
+
const queryParams = useMemo(() => new URLSearchParams(search), [search]);
|
13
|
+
|
14
|
+
const page = +queryParams.get('page') || 0;
|
15
|
+
const size = +queryParams.get('size') || 10;
|
16
|
+
|
17
|
+
const onPageChange = (newPage: number) => {
|
18
|
+
queryParams.set('page', `${newPage}`);
|
19
|
+
history.replace({ pathname: history.location.pathname, search: queryParams.toString() });
|
20
|
+
};
|
21
|
+
|
22
|
+
const onSizeChange = (count: number) => {
|
23
|
+
queryParams.set('size', `${count}`);
|
24
|
+
history.replace({ pathname: history.location.pathname, search: queryParams.toString() });
|
25
|
+
};
|
26
|
+
|
27
|
+
useEffect(() => {
|
28
|
+
if (mode === 'server') {
|
29
|
+
if (!queryParams.has('page')) {
|
30
|
+
queryParams.set('page', '0');
|
31
|
+
}
|
32
|
+
|
33
|
+
if (!queryParams.has('size')) {
|
34
|
+
queryParams.set('size', `10`);
|
35
|
+
}
|
36
|
+
|
37
|
+
history.replace({ pathname: history.location.pathname, search: queryParams.toString() }, state);
|
38
|
+
}
|
39
|
+
}, [search, mode]);
|
40
|
+
|
41
|
+
return {
|
42
|
+
page,
|
43
|
+
size,
|
44
|
+
onPageChange,
|
45
|
+
onSizeChange,
|
46
|
+
};
|
47
|
+
};
|
48
|
+
|
49
|
+
export default useTableQueryPagination;
|
@@ -0,0 +1,52 @@
|
|
1
|
+
import { useMemo } from 'react';
|
2
|
+
import { useHistory, useLocation } from 'react-router-dom';
|
3
|
+
import { GridColumnHeaderParams, GridColumns } from '@mui/x-data-grid';
|
4
|
+
|
5
|
+
export const useTableQuerySorting = () => {
|
6
|
+
const history = useHistory();
|
7
|
+
const { search, state } = useLocation();
|
8
|
+
|
9
|
+
const queryParams = useMemo(() => new URLSearchParams(search), [search]);
|
10
|
+
const sortParams = queryParams.getAll('sort').map((param) => param.split(','));
|
11
|
+
|
12
|
+
const onColumnHeaderClick = ({ field }: GridColumnHeaderParams) => {
|
13
|
+
let keyFound = false;
|
14
|
+
|
15
|
+
const sortValues = queryParams.getAll('sort');
|
16
|
+
queryParams.delete('sort');
|
17
|
+
|
18
|
+
sortValues.forEach((sortValue) => {
|
19
|
+
const [key, sort] = sortValue.split(',');
|
20
|
+
if (key === field) {
|
21
|
+
keyFound = true;
|
22
|
+
if (sort === 'asc') {
|
23
|
+
queryParams.append('sort', `${key},desc`);
|
24
|
+
}
|
25
|
+
} else {
|
26
|
+
queryParams.append('sort', `${key},${sort}`);
|
27
|
+
}
|
28
|
+
});
|
29
|
+
|
30
|
+
if (!keyFound) {
|
31
|
+
queryParams.append('sort', `${field},asc`);
|
32
|
+
}
|
33
|
+
|
34
|
+
history.replace({ pathname: history.location.pathname, search: queryParams.toString() }, state);
|
35
|
+
};
|
36
|
+
|
37
|
+
const getSortedColumns = (columns: GridColumns): GridColumns => {
|
38
|
+
return columns.map((column) => {
|
39
|
+
const columnSort = sortParams.find((param) => param[0] === column.field);
|
40
|
+
if (columnSort) {
|
41
|
+
column.headerClassName = `Sorted --${columnSort[1]} `;
|
42
|
+
} else {
|
43
|
+
column.headerClassName = '';
|
44
|
+
}
|
45
|
+
return column;
|
46
|
+
});
|
47
|
+
};
|
48
|
+
|
49
|
+
return { onColumnHeaderClick, getSortedColumns };
|
50
|
+
};
|
51
|
+
|
52
|
+
export default useTableQuerySorting;
|
@@ -0,0 +1,54 @@
|
|
1
|
+
import { useMemo } from 'react';
|
2
|
+
import Box from '@material-ui/core/Box';
|
3
|
+
import Paper from '@material-ui/core/Paper';
|
4
|
+
import Tab from '@material-ui/core/Tab';
|
5
|
+
import Tabs from '@material-ui/core/Tabs';
|
6
|
+
import TabPanel from './TabPanel';
|
7
|
+
|
8
|
+
import { useHistory, useLocation } from 'react-router-dom';
|
9
|
+
|
10
|
+
interface RouteTab {
|
11
|
+
name: string;
|
12
|
+
label: string;
|
13
|
+
component: React.ReactElement;
|
14
|
+
}
|
15
|
+
|
16
|
+
interface Props {
|
17
|
+
tabs: RouteTab[];
|
18
|
+
}
|
19
|
+
|
20
|
+
export const RouteTabs = (props: Props) => {
|
21
|
+
const { tabs } = props;
|
22
|
+
|
23
|
+
const history = useHistory();
|
24
|
+
const location = useLocation();
|
25
|
+
|
26
|
+
const queryParams = useMemo(() => new URLSearchParams(location.search), [location.search]);
|
27
|
+
const value = queryParams.get('tab');
|
28
|
+
|
29
|
+
const handleChange = (event, newValue: string) => {
|
30
|
+
queryParams.set('tab', newValue);
|
31
|
+
history.replace({ pathname: history.location.pathname, search: queryParams.toString() });
|
32
|
+
};
|
33
|
+
|
34
|
+
return (
|
35
|
+
<Box>
|
36
|
+
<Paper>
|
37
|
+
<Tabs value={value || tabs[0]?.name} indicatorColor="primary" textColor="primary" onChange={handleChange}>
|
38
|
+
{tabs.map((tab) => (
|
39
|
+
<Tab key={tab.name} value={tab.name} label={tab.label} />
|
40
|
+
))}
|
41
|
+
</Tabs>
|
42
|
+
</Paper>
|
43
|
+
<Box mt={2}>
|
44
|
+
{tabs.map((tab) => (
|
45
|
+
<TabPanel key={tab.name} value={value || tabs[0]?.name} index={tab.name}>
|
46
|
+
{tab.component}
|
47
|
+
</TabPanel>
|
48
|
+
))}
|
49
|
+
</Box>
|
50
|
+
</Box>
|
51
|
+
);
|
52
|
+
};
|
53
|
+
|
54
|
+
export default RouteTabs;
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* This interface is referencing the [[TabPanel]] component props.
|
5
|
+
* @category Common UI components
|
6
|
+
*/
|
7
|
+
export interface TabPanelProps {
|
8
|
+
/**
|
9
|
+
* Active tab value
|
10
|
+
*/
|
11
|
+
value: number | string;
|
12
|
+
/**
|
13
|
+
* Index of current panel
|
14
|
+
*/
|
15
|
+
index: number | string;
|
16
|
+
/**
|
17
|
+
* Rendered children component
|
18
|
+
*/
|
19
|
+
children: React.ReactElement;
|
20
|
+
}
|
21
|
+
|
22
|
+
/**
|
23
|
+
* Tab panel component. Used with tabs component
|
24
|
+
* @category Common UI components
|
25
|
+
*/
|
26
|
+
export const TabPanel = (props: TabPanelProps) => {
|
27
|
+
const { children, value, index, ...other } = props;
|
28
|
+
|
29
|
+
return (
|
30
|
+
<div
|
31
|
+
role="tabpanel"
|
32
|
+
hidden={value !== index}
|
33
|
+
id={`simple-tabpanel-${index}`}
|
34
|
+
aria-labelledby={`simple-tab-${index}`}
|
35
|
+
{...other}
|
36
|
+
>
|
37
|
+
{value === index ? children : null}
|
38
|
+
</div>
|
39
|
+
);
|
40
|
+
};
|
41
|
+
|
42
|
+
export default TabPanel;
|
@@ -0,0 +1,144 @@
|
|
1
|
+
import MUIRichTextEditor from 'mui-rte';
|
2
|
+
import { createTheme, ThemeProvider } from '@material-ui/core/styles';
|
3
|
+
import { ContentState, EditorState, Modifier, convertFromHTML, convertToRaw } from 'draft-js';
|
4
|
+
import FunctionsIcon from '@material-ui/icons/Functions';
|
5
|
+
import Typography from '@material-ui/core/Typography';
|
6
|
+
import ExpressionDecorator from './ExpressionDecorator';
|
7
|
+
import { JsonPathPicker } from '../JsonPathPicker';
|
8
|
+
|
9
|
+
import { useEffect, useState } from 'react';
|
10
|
+
// import { stateToHTML } from 'draft-js-export-html';
|
11
|
+
import { useToggle } from '../../utils';
|
12
|
+
import { JsonPathPickerProperties, PropertiesArrayType } from '../../interfaces';
|
13
|
+
import { useController, useFormContext } from 'react-hook-form';
|
14
|
+
|
15
|
+
type Props = {
|
16
|
+
fieldName: string;
|
17
|
+
getProperties?: () => JsonPathPickerProperties;
|
18
|
+
initialText?: string;
|
19
|
+
};
|
20
|
+
|
21
|
+
const defaultTheme = createTheme();
|
22
|
+
|
23
|
+
Object.assign(defaultTheme, {
|
24
|
+
overrides: {
|
25
|
+
MUIRichTextEditor: {
|
26
|
+
root: {
|
27
|
+
marginTop: 20,
|
28
|
+
width: '100%',
|
29
|
+
border: '1px solid gray',
|
30
|
+
padding: '8px',
|
31
|
+
},
|
32
|
+
editor: {
|
33
|
+
minHeight: '300px',
|
34
|
+
},
|
35
|
+
toolbar: {
|
36
|
+
backgroundColor: '#eee',
|
37
|
+
},
|
38
|
+
},
|
39
|
+
},
|
40
|
+
});
|
41
|
+
|
42
|
+
export const TemplateContentEditor = ({ fieldName, getProperties, initialText }: Props) => {
|
43
|
+
const { control, setValue, clearErrors } = useFormContext();
|
44
|
+
const {
|
45
|
+
fieldState: { error },
|
46
|
+
} = useController({
|
47
|
+
control,
|
48
|
+
name: fieldName,
|
49
|
+
rules: {
|
50
|
+
required: 'Please, fill content',
|
51
|
+
},
|
52
|
+
});
|
53
|
+
|
54
|
+
const defaultContent = convertToRaw(EditorState.createEmpty().getCurrentContent());
|
55
|
+
const { open: jsonPathPickerOpen, onOpen: onJsonPathPickerOpen, onClose: onJsonPathPickerClose } = useToggle();
|
56
|
+
|
57
|
+
const [content, setContent] = useState(JSON.stringify(defaultContent));
|
58
|
+
const [properties, setProperties] = useState<
|
59
|
+
{
|
60
|
+
properties: PropertiesArrayType;
|
61
|
+
pathPrefix: string;
|
62
|
+
title: string;
|
63
|
+
}[]
|
64
|
+
>([]);
|
65
|
+
const [editorState, setEditorState] = useState<EditorState>(null);
|
66
|
+
|
67
|
+
useEffect(() => {
|
68
|
+
if (initialText) {
|
69
|
+
const contentState = convertFromHTML(initialText);
|
70
|
+
const state =
|
71
|
+
contentState && ContentState.createFromBlockArray(contentState.contentBlocks, contentState.entityMap);
|
72
|
+
setContent(JSON.stringify(convertToRaw(state)));
|
73
|
+
}
|
74
|
+
}, [initialText]);
|
75
|
+
|
76
|
+
const handleChange = (state: EditorState) => {
|
77
|
+
const currentContentState = state.getCurrentContent();
|
78
|
+
const selectionState = state.getSelection();
|
79
|
+
EditorState.push(state, Modifier.replaceText(currentContentState, selectionState, ''), 'remove-range');
|
80
|
+
|
81
|
+
const isEmpty = !state.getCurrentContent().hasText();
|
82
|
+
const content = currentContentState.getPlainText();
|
83
|
+
// stateToHTML(currentContentState);
|
84
|
+
|
85
|
+
setValue(fieldName, !isEmpty ? content : '');
|
86
|
+
clearErrors(fieldName);
|
87
|
+
};
|
88
|
+
|
89
|
+
const handleJsonPathPickerClick = (eState) => {
|
90
|
+
setEditorState(eState);
|
91
|
+
setProperties(getProperties());
|
92
|
+
onJsonPathPickerOpen();
|
93
|
+
};
|
94
|
+
|
95
|
+
const handleJsonPathPaste = (jsonPath: string) => {
|
96
|
+
const currentContentState = editorState.getCurrentContent();
|
97
|
+
const selectionState = editorState.getSelection();
|
98
|
+
|
99
|
+
const state = EditorState.push(
|
100
|
+
editorState,
|
101
|
+
Modifier.insertText(currentContentState, selectionState, jsonPath),
|
102
|
+
'insert-characters'
|
103
|
+
).getCurrentContent();
|
104
|
+
|
105
|
+
setContent(JSON.stringify(convertToRaw(state)));
|
106
|
+
onJsonPathPickerClose();
|
107
|
+
};
|
108
|
+
|
109
|
+
return (
|
110
|
+
<ThemeProvider theme={defaultTheme}>
|
111
|
+
<MUIRichTextEditor
|
112
|
+
defaultValue={content}
|
113
|
+
label="Start here..."
|
114
|
+
controls={['title', 'bold', 'italic', 'strikethrough', 'numberList', 'bulletList', 'code', 'jsonPathPicker']}
|
115
|
+
onChange={handleChange}
|
116
|
+
customControls={[
|
117
|
+
{
|
118
|
+
name: 'jsonPathPicker',
|
119
|
+
icon: <FunctionsIcon />,
|
120
|
+
type: 'callback',
|
121
|
+
onClick: handleJsonPathPickerClick,
|
122
|
+
},
|
123
|
+
]}
|
124
|
+
decorators={[
|
125
|
+
{
|
126
|
+
component: ExpressionDecorator,
|
127
|
+
regex: /\$\([^\s]*\)/g,
|
128
|
+
},
|
129
|
+
]}
|
130
|
+
/>
|
131
|
+
<Typography color="secondary">{error?.message}</Typography>
|
132
|
+
{jsonPathPickerOpen && (
|
133
|
+
<JsonPathPicker
|
134
|
+
open={jsonPathPickerOpen}
|
135
|
+
properties={properties}
|
136
|
+
onClose={onJsonPathPickerClose}
|
137
|
+
onPaste={handleJsonPathPaste}
|
138
|
+
/>
|
139
|
+
)}
|
140
|
+
</ThemeProvider>
|
141
|
+
);
|
142
|
+
};
|
143
|
+
|
144
|
+
export default TemplateContentEditor;
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from './TemplateContentEditor';
|
package/src/lib/index.ts
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
export * from './Alert';
|
2
|
+
export * from './Forms';
|
3
|
+
export * from './Loader';
|
4
|
+
export * from './Table';
|
5
|
+
export * from './Tabs';
|
6
|
+
export * from './DemPropertyField';
|
7
|
+
export * from './Modals';
|
8
|
+
export * from './InfoItem';
|
9
|
+
export * from './Definition';
|
10
|
+
export * from './Property';
|
11
|
+
export * from './Status';
|
12
|
+
export * from './JsonView';
|
13
|
+
export * from './JsonPathPicker';
|
14
|
+
export * from './TemplateContent';
|
@@ -0,0 +1,68 @@
|
|
1
|
+
export const removeArrayItem = (arr: Array<unknown>, index: number) => {
|
2
|
+
const newArr = [...arr];
|
3
|
+
newArr.splice(index, 1);
|
4
|
+
return newArr;
|
5
|
+
};
|
6
|
+
|
7
|
+
export const validateJson = (value: string): boolean => {
|
8
|
+
try {
|
9
|
+
JSON.parse(value);
|
10
|
+
} catch (error) {
|
11
|
+
return false;
|
12
|
+
}
|
13
|
+
return true;
|
14
|
+
};
|
15
|
+
|
16
|
+
export function capitalize(str: string): string {
|
17
|
+
return str.replace(/(^\w)|([-\s]\w)/g, (c) => c.toUpperCase());
|
18
|
+
}
|
19
|
+
|
20
|
+
export const sortArrayOfObjects = (a: any, b: any, key: string, order = 'asc') => {
|
21
|
+
const valueA = a[key];
|
22
|
+
const valueB = b[key];
|
23
|
+
|
24
|
+
if (valueA < valueB) return order === 'asc' ? -1 : 1;
|
25
|
+
if (valueA > valueB) return order === 'asc' ? 1 : -1;
|
26
|
+
return 0;
|
27
|
+
};
|
28
|
+
|
29
|
+
export const getJsonStringValue = (value: unknown): string => {
|
30
|
+
if (!value) return '';
|
31
|
+
if (typeof value !== 'string') {
|
32
|
+
try {
|
33
|
+
return JSON.stringify(value, null, '\t');
|
34
|
+
} catch (error) {
|
35
|
+
return 'Failed to stringify JSON';
|
36
|
+
}
|
37
|
+
}
|
38
|
+
return value;
|
39
|
+
};
|
40
|
+
|
41
|
+
export const safeParseJson = (value: string) => {
|
42
|
+
try {
|
43
|
+
return JSON.parse(value);
|
44
|
+
} catch (error) {
|
45
|
+
return null;
|
46
|
+
}
|
47
|
+
};
|
48
|
+
|
49
|
+
export const deepParseJson = (value: string) => {
|
50
|
+
try {
|
51
|
+
const parsedValue = JSON.parse(value);
|
52
|
+
Object.keys(parsedValue).forEach((key) => {
|
53
|
+
parsedValue[key] = deepParseJson(parsedValue[key]);
|
54
|
+
});
|
55
|
+
return parsedValue;
|
56
|
+
} catch (error) {
|
57
|
+
return value;
|
58
|
+
}
|
59
|
+
};
|
60
|
+
|
61
|
+
// export const convertArrayToObjectByKey = (array: { [key: string]: string }[], key: string) => {
|
62
|
+
// const obj = {};
|
63
|
+
// array.forEach((el) => {
|
64
|
+
// obj[el[key]] = { ...el };
|
65
|
+
// delete obj[el[key]][key];
|
66
|
+
// });
|
67
|
+
// return obj;
|
68
|
+
// };
|
package/src/utils/dem.ts
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
import { PropertyType, EntityTypeProperty, PropertiesArrayType } from '../interfaces';
|
2
|
+
import { sortArrayOfObjects } from './common';
|
3
|
+
import { format } from 'date-fns';
|
4
|
+
|
5
|
+
export const isExpression = (value: unknown): boolean => {
|
6
|
+
return typeof value === 'string' ? value.startsWith('$') : false;
|
7
|
+
};
|
8
|
+
|
9
|
+
export function propertiesObjectToArray(properties, fields?: { [key: string]: unknown }) {
|
10
|
+
return Object.keys(properties)
|
11
|
+
.map((key) => {
|
12
|
+
const propObj = { key, ...properties[key], ...(fields ? fields : {}) };
|
13
|
+
if (propObj['propertyType'] === PropertyType.ENTITY) {
|
14
|
+
propObj['properties'] = propertiesObjectToArray(propObj['properties'], fields);
|
15
|
+
}
|
16
|
+
|
17
|
+
if (propObj['propertyType'] === PropertyType.JSON) {
|
18
|
+
try {
|
19
|
+
propObj.defaultValue = JSON.stringify(propObj.defaultValue);
|
20
|
+
} catch (error) {
|
21
|
+
propObj.defaultValue = '';
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
if (propObj['uiSettings']) {
|
26
|
+
try {
|
27
|
+
propObj.uiSettings = JSON.stringify(propObj.uiSettings);
|
28
|
+
} catch (error) {
|
29
|
+
propObj.uiSettings = '';
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
if (propObj['isMultiple']) {
|
34
|
+
if ('defaultValues' in propObj) {
|
35
|
+
propObj['defaultValue'] = propObj.defaultValues;
|
36
|
+
}
|
37
|
+
if ('values' in propObj) {
|
38
|
+
propObj['value'] = propObj.values;
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
return propObj;
|
43
|
+
})
|
44
|
+
.sort((a, b) => sortArrayOfObjects(a, b, 'sortOrder'));
|
45
|
+
}
|
46
|
+
|
47
|
+
export const getDemPropertyDateFormat = (defaultFormat: string, propertyFormat: string) => {
|
48
|
+
if (propertyFormat) {
|
49
|
+
try {
|
50
|
+
const correctFormat = propertyFormat.replace(/Z/g, 'XXX');
|
51
|
+
format(new Date(), correctFormat);
|
52
|
+
return correctFormat;
|
53
|
+
} catch (e) {
|
54
|
+
console.error('Incorrect format', e);
|
55
|
+
return defaultFormat;
|
56
|
+
}
|
57
|
+
}
|
58
|
+
return defaultFormat;
|
59
|
+
};
|
60
|
+
|
61
|
+
export const getEntityStarterValue = (property: EntityTypeProperty) => {
|
62
|
+
let properties: PropertiesArrayType = [];
|
63
|
+
if (Array.isArray(property.properties)) {
|
64
|
+
properties = property.properties;
|
65
|
+
} else {
|
66
|
+
properties = propertiesObjectToArray(property.properties);
|
67
|
+
}
|
68
|
+
|
69
|
+
return properties.reduce((value, property) => {
|
70
|
+
const result = JSON.parse(JSON.stringify(value));
|
71
|
+
if (property.propertyType === PropertyType.ENTITY) {
|
72
|
+
result[property.key] = getEntityStarterValue(property);
|
73
|
+
} else {
|
74
|
+
result[property.key] = property.propertyType;
|
75
|
+
}
|
76
|
+
return result;
|
77
|
+
}, {});
|
78
|
+
};
|
@@ -0,0 +1,41 @@
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
2
|
+
|
3
|
+
export function useDebounce(func: (args?: any) => void, delay: number) {
|
4
|
+
const timer = useRef<NodeJS.Timeout>();
|
5
|
+
|
6
|
+
useEffect(() => {
|
7
|
+
return () => {
|
8
|
+
if (!timer.current) return;
|
9
|
+
clearTimeout(timer.current);
|
10
|
+
};
|
11
|
+
}, []);
|
12
|
+
|
13
|
+
const debounceFunction = (...args) => {
|
14
|
+
clearTimeout(timer.current);
|
15
|
+
timer.current = setTimeout(() => {
|
16
|
+
func(...args);
|
17
|
+
}, delay);
|
18
|
+
};
|
19
|
+
|
20
|
+
return debounceFunction;
|
21
|
+
}
|
22
|
+
|
23
|
+
|
24
|
+
export const useToggle = () => {
|
25
|
+
const [open, setOpen] = useState(false);
|
26
|
+
|
27
|
+
const toggle = () => {
|
28
|
+
setOpen((prevState) => !prevState);
|
29
|
+
};
|
30
|
+
|
31
|
+
const onClose = () => {
|
32
|
+
setOpen(false);
|
33
|
+
};
|
34
|
+
|
35
|
+
const onOpen = () => {
|
36
|
+
setOpen(true);
|
37
|
+
};
|
38
|
+
|
39
|
+
return { open, toggle, onClose, onOpen };
|
40
|
+
};
|
41
|
+
|