@topconsultnpm/sdkui-react-beta 6.12.37 → 6.12.39
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/lib/components/base/Styled.d.ts +12 -0
- package/lib/components/base/Styled.js +49 -3
- package/lib/components/base/TMFloatingToolbar.d.ts +9 -0
- package/lib/components/base/TMFloatingToolbar.js +99 -0
- package/lib/components/base/TMRightSidebar.d.ts +0 -4
- package/lib/components/base/TMRightSidebar.js +2 -10
- package/lib/components/base/TMShowAllOrMaxItemsButton.d.ts +8 -0
- package/lib/components/base/TMShowAllOrMaxItemsButton.js +14 -0
- package/lib/components/base/TMTreeView.d.ts +27 -0
- package/lib/components/base/TMTreeView.js +199 -0
- package/lib/components/grids/TMBlogs.d.ts +84 -0
- package/lib/components/grids/TMBlogs.js +566 -0
- package/lib/components/grids/TMBlogsUtils.d.ts +83 -0
- package/lib/components/grids/TMBlogsUtils.js +258 -0
- package/lib/components/index.d.ts +2 -0
- package/lib/components/index.js +2 -0
- package/lib/components/query/TMBatchUpdateForm.d.ts +12 -0
- package/lib/components/query/TMBatchUpdateForm.js +149 -0
- package/lib/components/query/TMDcmtBlog.d.ts +7 -0
- package/lib/components/query/TMDcmtBlog.js +34 -0
- package/lib/components/query/TMDcmtForm.d.ts +32 -0
- package/lib/components/query/TMDcmtForm.js +544 -0
- package/lib/components/query/TMDcmtIcon.d.ts +10 -0
- package/lib/components/query/TMDcmtIcon.js +52 -0
- package/lib/components/query/TMDcmtPreview.d.ts +26 -0
- package/lib/components/query/TMDcmtPreview.js +200 -0
- package/lib/components/query/TMFileUploader.d.ts +11 -0
- package/lib/components/query/TMFileUploader.js +101 -0
- package/lib/components/query/TMMasterDetailDcmts.d.ts +23 -0
- package/lib/components/query/TMMasterDetailDcmts.js +475 -0
- package/lib/components/query/TMQueryEditor.js +2 -2
- package/lib/components/query/TMQueryResultForm.d.ts +1 -7
- package/lib/components/query/TMQueryResultForm.js +1 -9
- package/lib/components/query/TMWorkflowPopup.d.ts +29 -0
- package/lib/components/query/TMWorkflowPopup.js +131 -0
- package/lib/components/search/TMSearchResult.d.ts +31 -0
- package/lib/components/search/TMSearchResult.js +727 -0
- package/lib/components/search/TMSearchResultsMenuItems.d.ts +6 -0
- package/lib/components/search/TMSearchResultsMenuItems.js +376 -0
- package/lib/helper/Enum_Localizator.d.ts +2 -1
- package/lib/helper/Enum_Localizator.js +20 -1
- package/lib/helper/SDKUI_Localizator.d.ts +24 -0
- package/lib/helper/SDKUI_Localizator.js +240 -0
- package/lib/helper/dcmtsHelper.d.ts +4 -0
- package/lib/helper/dcmtsHelper.js +15 -0
- package/lib/helper/helpers.d.ts +2 -1
- package/lib/helper/helpers.js +74 -1
- package/lib/helper/queryHelper.d.ts +7 -1
- package/lib/helper/queryHelper.js +105 -1
- package/lib/hooks/useDcmtOperations.d.ts +24 -0
- package/lib/hooks/useDcmtOperations.js +387 -0
- package/lib/hooks/useInputDialog.d.ts +5 -0
- package/lib/hooks/useInputDialog.js +73 -0
- package/lib/hooks/usePreventFileDrop.d.ts +3 -0
- package/lib/hooks/usePreventFileDrop.js +37 -0
- package/lib/index.d.ts +0 -1
- package/lib/index.js +0 -1
- package/lib/services/platform_services.d.ts +1 -1
- package/lib/ts/types.d.ts +54 -1
- package/lib/ts/types.js +34 -0
- package/package.json +1 -1
@@ -0,0 +1,83 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { BlogPost, BlogPostAttachment, DcmtTypeDescriptor, HomeBlogPost } from "@topconsultnpm/sdk-ts-beta";
|
3
|
+
import { FileItem } from '../base/TMFileManager';
|
4
|
+
export declare const DRAFT_TYPE_TID = 6;
|
5
|
+
export declare const colors: {
|
6
|
+
DARK_BLUE: string;
|
7
|
+
WHITE: string;
|
8
|
+
BLACK: string;
|
9
|
+
RED: string;
|
10
|
+
LIGHT_GRAY: string;
|
11
|
+
PRIMARY_BLUE: string;
|
12
|
+
PRIMARY_ORANGE: string;
|
13
|
+
PRIMARY_GREEN: string;
|
14
|
+
};
|
15
|
+
export interface TMBlogContextMenuItem {
|
16
|
+
text: string;
|
17
|
+
icon: string;
|
18
|
+
onClick?: (param?: any) => void;
|
19
|
+
operationType?: 'singleRow' | 'multiRow';
|
20
|
+
disabled?: boolean;
|
21
|
+
id?: string;
|
22
|
+
items?: Array<TMBlogContextMenuItem>;
|
23
|
+
beginGroup?: boolean;
|
24
|
+
tooltip?: string;
|
25
|
+
visible?: boolean;
|
26
|
+
}
|
27
|
+
export declare enum TMBlogsFilterCategoryId {
|
28
|
+
PublishedBlogs = 1,
|
29
|
+
SystemBlogs = 2,
|
30
|
+
DeletedBlogs = 3
|
31
|
+
}
|
32
|
+
export interface BlogPostContainerProps {
|
33
|
+
$color?: string;
|
34
|
+
$textDecoration?: string;
|
35
|
+
$backgroundColor?: string;
|
36
|
+
$isNew?: boolean;
|
37
|
+
$canNavigate?: boolean;
|
38
|
+
}
|
39
|
+
export declare const BlogPostContainer: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, BlogPostContainerProps>> & string;
|
40
|
+
export declare const getTooltipContent: (title: string | undefined, content: JSX.Element) => import("react/jsx-runtime").JSX.Element;
|
41
|
+
export declare const highlightText: (text: string, searchText: string, isSelected: boolean) => string | (string | import("react/jsx-runtime").JSX.Element)[];
|
42
|
+
export declare const lightenColor: (hex: string, amount: number) => string;
|
43
|
+
export declare const removeFileExtension: (filename: string) => string;
|
44
|
+
export declare const getAttachmentInfo: (attachment: BlogPostAttachment, treeFs: FileItem | undefined, draftLatestInfoMap: Map<number, {
|
45
|
+
latestVersion: number;
|
46
|
+
folderId: number;
|
47
|
+
folderName: string;
|
48
|
+
fileExt: string;
|
49
|
+
fileSize: string;
|
50
|
+
}> | undefined, archivedDocumentMap: Map<number, {
|
51
|
+
tid: number;
|
52
|
+
did: number;
|
53
|
+
fileExt: string;
|
54
|
+
fileSize: string;
|
55
|
+
}> | undefined, dcmtTypeDescriptors: Map<number, DcmtTypeDescriptor>, isSelected: boolean, searchText: string, color: string) => {
|
56
|
+
name: string;
|
57
|
+
nameElement: import("react/jsx-runtime").JSX.Element;
|
58
|
+
folderId: number;
|
59
|
+
fileExt: string;
|
60
|
+
draftExist: boolean;
|
61
|
+
archivedDocumentsExist: boolean;
|
62
|
+
};
|
63
|
+
export declare const AttachmentElement: (attachment: BlogPostAttachment, treeFs: FileItem | undefined, draftLatestInfoMap: Map<number, {
|
64
|
+
latestVersion: number;
|
65
|
+
folderId: number;
|
66
|
+
folderName: string;
|
67
|
+
fileExt: string;
|
68
|
+
fileSize: string;
|
69
|
+
}> | undefined, archivedDocumentMap: Map<number, {
|
70
|
+
tid: number;
|
71
|
+
did: number;
|
72
|
+
fileExt: string;
|
73
|
+
fileSize: string;
|
74
|
+
}> | undefined, dcmtTypeDescriptors: Map<number, DcmtTypeDescriptor>, isSelected: boolean, searchText: string, color: string, handleClickAttachmentFolderFileCallback: ((folderId: number, draftId: number) => void) | undefined, downloadDcmtsAsync: (inputDcmts: Array<any> | undefined) => Promise<void>) => import("react/jsx-runtime").JSX.Element;
|
75
|
+
export declare const OwnerInitialsBadge: (blogPost: BlogPost | HomeBlogPost) => import("react/jsx-runtime").JSX.Element;
|
76
|
+
export declare const IconAndHeaderElement: (blogPost: BlogPost | HomeBlogPost, iconColor: string, isSelected: boolean, headerClickCallback: () => void, searchText: string) => import("react/jsx-runtime").JSX.Element;
|
77
|
+
export declare const findFileItemByDraftID: (tree: FileItem | undefined, draftID: number | undefined) => FileItem | null;
|
78
|
+
export declare const isHeaderFullyHidden: (header: {
|
79
|
+
showViewMode: boolean;
|
80
|
+
showFilters: boolean;
|
81
|
+
showSearchBar: boolean;
|
82
|
+
showPostsDropDown: boolean;
|
83
|
+
} | undefined) => boolean;
|
@@ -0,0 +1,258 @@
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
2
|
+
import styled from "styled-components";
|
3
|
+
import { SDK_Globals } from "@topconsultnpm/sdk-ts-beta";
|
4
|
+
import { formatBytes, getFileIcon, IconAttachment, IconUserGroup, IconWorkspace, SDKUI_Localizator } from "../../helper";
|
5
|
+
import TMTooltip from "../base/TMTooltip";
|
6
|
+
export const DRAFT_TYPE_TID = 6;
|
7
|
+
export const colors = {
|
8
|
+
DARK_BLUE: "#1a0dab",
|
9
|
+
WHITE: "#fff",
|
10
|
+
BLACK: "#000000",
|
11
|
+
RED: '#ff0000',
|
12
|
+
LIGHT_GRAY: "#f9f9f9",
|
13
|
+
PRIMARY_BLUE: "#135596",
|
14
|
+
PRIMARY_ORANGE: "#e65b00",
|
15
|
+
PRIMARY_GREEN: "#009700"
|
16
|
+
};
|
17
|
+
export var TMBlogsFilterCategoryId;
|
18
|
+
(function (TMBlogsFilterCategoryId) {
|
19
|
+
TMBlogsFilterCategoryId[TMBlogsFilterCategoryId["PublishedBlogs"] = 1] = "PublishedBlogs";
|
20
|
+
TMBlogsFilterCategoryId[TMBlogsFilterCategoryId["SystemBlogs"] = 2] = "SystemBlogs";
|
21
|
+
TMBlogsFilterCategoryId[TMBlogsFilterCategoryId["DeletedBlogs"] = 3] = "DeletedBlogs";
|
22
|
+
})(TMBlogsFilterCategoryId || (TMBlogsFilterCategoryId = {}));
|
23
|
+
export const BlogPostContainer = styled.div `
|
24
|
+
color: ${(props) => (props.$color ?? colors.BLACK)};
|
25
|
+
text-decoration: ${(props) => (props.$textDecoration ?? 'none')};
|
26
|
+
height: auto;
|
27
|
+
background-color: ${(props) => (props.$backgroundColor ?? colors.WHITE)};
|
28
|
+
display: inline-block;
|
29
|
+
width: 100%;
|
30
|
+
max-width: 100%;
|
31
|
+
cursor: ${(props) => (props.$canNavigate ? "pointer" : "default")};
|
32
|
+
border-radius: 5px;
|
33
|
+
margin: 5px 0;
|
34
|
+
padding: 10px;
|
35
|
+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
|
36
|
+
word-wrap: break-word;
|
37
|
+
white-space: pre-wrap;
|
38
|
+
font-weight: ${(props) => (props.$isNew ? 'bold' : 'normal')};
|
39
|
+
&:focus {
|
40
|
+
outline: none;
|
41
|
+
}
|
42
|
+
`;
|
43
|
+
export const getTooltipContent = (title, content) => {
|
44
|
+
return (_jsxs("div", { style: { textAlign: 'left' }, children: [_jsx("div", { style: { fontWeight: 'bold' }, children: title }), _jsx("hr", {}), content] }));
|
45
|
+
};
|
46
|
+
export const highlightText = (text, searchText, isSelected) => {
|
47
|
+
if (!searchText)
|
48
|
+
return text;
|
49
|
+
const regex = new RegExp(`(${searchText.trim()})`, 'gi');
|
50
|
+
return text.split(regex).map((part, index) => regex.test(part) ? (_jsx("span", { style: { backgroundColor: isSelected ? '#6c9023' : 'yellow' }, children: part }, index)) : (part));
|
51
|
+
};
|
52
|
+
export const lightenColor = (hex, amount) => {
|
53
|
+
let color = hex.replace('#', '');
|
54
|
+
// Expand shorthand like #123 to #112233
|
55
|
+
if (color.length === 3) {
|
56
|
+
color = color.split('').map(c => c + c).join('');
|
57
|
+
}
|
58
|
+
const num = parseInt(color, 16);
|
59
|
+
let r = (num >> 16) + amount;
|
60
|
+
let g = ((num >> 8) & 0x00FF) + amount;
|
61
|
+
let b = (num & 0x0000FF) + amount;
|
62
|
+
r = Math.min(255, Math.max(0, r));
|
63
|
+
g = Math.min(255, Math.max(0, g));
|
64
|
+
b = Math.min(255, Math.max(0, b));
|
65
|
+
return `#${(r << 16 | g << 8 | b).toString(16).padStart(6, '0')}`;
|
66
|
+
};
|
67
|
+
export const removeFileExtension = (filename) => {
|
68
|
+
return filename.includes('.') ? filename.substring(0, filename.lastIndexOf('.')) : filename;
|
69
|
+
};
|
70
|
+
export const getAttachmentInfo = (attachment, treeFs, draftLatestInfoMap, archivedDocumentMap, dcmtTypeDescriptors, isSelected, searchText, color) => {
|
71
|
+
let nameElement = (_jsx("span", { children: `${SDKUI_Localizator.DocumentNotAvailable} (DID: ${attachment.did})` }));
|
72
|
+
let folderId = -1;
|
73
|
+
let fileExt = '';
|
74
|
+
let draftExist = false;
|
75
|
+
let archivedDocumentsExist = false;
|
76
|
+
let name = '';
|
77
|
+
if (attachment.tid === DRAFT_TYPE_TID && treeFs) {
|
78
|
+
const draftfileItem = findFileItemByDraftID(treeFs, attachment.draftID);
|
79
|
+
if (draftfileItem) {
|
80
|
+
let latestVersion = true;
|
81
|
+
let pathName = '';
|
82
|
+
draftExist = true;
|
83
|
+
let fileSize = '0';
|
84
|
+
name = draftfileItem.name;
|
85
|
+
if (draftLatestInfoMap && attachment.draftID && attachment.version) {
|
86
|
+
const draftInfo = draftLatestInfoMap.get(attachment.draftID);
|
87
|
+
if (draftInfo) {
|
88
|
+
folderId = draftInfo.folderId;
|
89
|
+
latestVersion = draftInfo.latestVersion === attachment.version;
|
90
|
+
pathName = draftInfo.folderName;
|
91
|
+
fileExt = draftInfo.fileExt;
|
92
|
+
fileSize = formatBytes(draftInfo.fileSize ? Number(draftInfo.fileSize) : 0);
|
93
|
+
}
|
94
|
+
}
|
95
|
+
const content = (_jsxs("div", { children: [_jsxs("div", { children: [_jsx("span", { style: { fontWeight: 'bold' }, children: SDKUI_Localizator.Version }), ": ", attachment.version] }), draftLatestInfoMap && (_jsxs("div", { children: [_jsxs("div", { children: [_jsx("span", { style: { fontWeight: 'bold' }, children: SDKUI_Localizator.LastVersion }), ": ", latestVersion ? SDKUI_Localizator.Yes : SDKUI_Localizator.No] }), _jsxs("div", { children: [_jsx("span", { style: { fontWeight: 'bold' }, children: SDKUI_Localizator.Size }), ": ", fileSize] })] })), _jsx("hr", {}), _jsxs("div", { children: [_jsx("span", { style: { fontWeight: 'bold' }, children: SDKUI_Localizator.Path }), ": \"", SDKUI_Localizator.Drafts, "\\", pathName.length > 0 ? (pathName + '\\') : '', name, "\""] })] }));
|
96
|
+
const tooltipContent = getTooltipContent(draftfileItem.name, content);
|
97
|
+
nameElement = (_jsx("span", { children: _jsxs(TMTooltip, { content: tooltipContent, children: [highlightText(`${draftfileItem.name} (DID: ${attachment.did})`, searchText, isSelected), "\u00A0", _jsx("span", { style: {
|
98
|
+
display: 'inline-flex',
|
99
|
+
marginLeft: '5px',
|
100
|
+
width: '20px',
|
101
|
+
height: '20px',
|
102
|
+
alignItems: 'center',
|
103
|
+
justifyContent: 'center',
|
104
|
+
backgroundColor: isSelected ? '#fff' : (latestVersion ? '#28a745' : '#cc7000'),
|
105
|
+
color: isSelected ? color : '#fff',
|
106
|
+
boxShadow: '1px 1px 2px #00000020',
|
107
|
+
borderRadius: '30px',
|
108
|
+
fontWeight: 'bold',
|
109
|
+
}, children: attachment.version })] }) }));
|
110
|
+
}
|
111
|
+
}
|
112
|
+
else if (attachment.tid) {
|
113
|
+
const descriptor = dcmtTypeDescriptors.get(attachment.tid);
|
114
|
+
let fileSize = '0';
|
115
|
+
if (archivedDocumentMap && attachment.did) {
|
116
|
+
const archivedDocumentInfo = archivedDocumentMap.get(attachment.did);
|
117
|
+
if (archivedDocumentInfo) {
|
118
|
+
archivedDocumentsExist = true;
|
119
|
+
fileExt = archivedDocumentInfo.fileExt;
|
120
|
+
fileSize = formatBytes(archivedDocumentInfo.fileSize ? Number(archivedDocumentInfo.fileSize) : 0);
|
121
|
+
}
|
122
|
+
}
|
123
|
+
if (descriptor) {
|
124
|
+
name = descriptor.name ?? "-";
|
125
|
+
const content = (_jsxs("div", { children: [archivedDocumentMap && (_jsxs("div", { children: [_jsx("span", { style: { fontWeight: 'bold' }, children: SDKUI_Localizator.Size }), ": ", fileSize] })), _jsx("hr", {}), _jsxs("div", { children: [_jsx("span", { style: { fontWeight: 'bold' }, children: SDKUI_Localizator.Path }), ": \"", SDKUI_Localizator.ArchivedDocuments, "\\", `${descriptor.name} (DID: ${attachment.did})`, "\""] })] }));
|
126
|
+
const tooltipContent = getTooltipContent(descriptor.name, content);
|
127
|
+
nameElement = (_jsx("span", { children: _jsx(TMTooltip, { content: tooltipContent, children: highlightText(`${name} (DID: ${attachment.did})`, searchText, isSelected) }) }));
|
128
|
+
}
|
129
|
+
}
|
130
|
+
return { name, nameElement, folderId, fileExt, draftExist, archivedDocumentsExist };
|
131
|
+
};
|
132
|
+
export const AttachmentElement = (attachment, treeFs, draftLatestInfoMap, archivedDocumentMap, dcmtTypeDescriptors, isSelected, searchText, color, handleClickAttachmentFolderFileCallback, downloadDcmtsAsync) => {
|
133
|
+
const { name, nameElement, folderId, fileExt, draftExist } = getAttachmentInfo(attachment, treeFs, draftLatestInfoMap, archivedDocumentMap, dcmtTypeDescriptors, isSelected, searchText, color);
|
134
|
+
const onClickCallback = (e) => {
|
135
|
+
e.preventDefault();
|
136
|
+
e.stopPropagation();
|
137
|
+
if (attachment.tid === DRAFT_TYPE_TID && treeFs && draftExist) {
|
138
|
+
const folderIdAttachment = folderId === 0 ? -1 : folderId;
|
139
|
+
if (handleClickAttachmentFolderFileCallback && attachment.draftID)
|
140
|
+
handleClickAttachmentFolderFileCallback(folderIdAttachment, attachment.draftID);
|
141
|
+
}
|
142
|
+
};
|
143
|
+
const onDoubleClick = (e) => {
|
144
|
+
e.preventDefault();
|
145
|
+
e.stopPropagation();
|
146
|
+
const archiveID = SDK_Globals.tmSession?.SessionDescr?.archiveID;
|
147
|
+
const fileName = `${removeFileExtension(name)}_${archiveID}_${attachment.tid}_${attachment.did}.${fileExt}`;
|
148
|
+
if (downloadDcmtsAsync)
|
149
|
+
downloadDcmtsAsync([{ TID: attachment.tid, DID: attachment.did, fileName }]);
|
150
|
+
};
|
151
|
+
return _jsx("div", { onClick: onClickCallback, onDoubleClick: onDoubleClick, style: {
|
152
|
+
display: 'inline-flex',
|
153
|
+
padding: '8px 12px',
|
154
|
+
margin: '4px',
|
155
|
+
border: '1px solid #ddd',
|
156
|
+
borderRadius: '8px',
|
157
|
+
boxShadow: '0 2px 4px rgba(0, 0, 0, 0.1)',
|
158
|
+
backgroundColor: isSelected ? color : colors.WHITE,
|
159
|
+
cursor: "pointer"
|
160
|
+
}, onMouseEnter: (e) => {
|
161
|
+
e.currentTarget.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.15)';
|
162
|
+
e.currentTarget.style.backgroundColor = isSelected ? lightenColor(color, 40) : '#cfcfcf';
|
163
|
+
}, onMouseLeave: (e) => {
|
164
|
+
e.currentTarget.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.1)';
|
165
|
+
e.currentTarget.style.backgroundColor = isSelected ? color : colors.WHITE;
|
166
|
+
}, children: _jsxs("div", { style: { alignItems: 'center', display: 'flex' }, children: [fileExt ? _jsx("span", { style: { marginRight: "10px" }, children: getFileIcon(fileExt, undefined) }) : _jsx(IconAttachment, { style: { marginRight: "5px" } }), _jsx("span", { children: nameElement })] }) }, attachment.did);
|
167
|
+
};
|
168
|
+
export const OwnerInitialsBadge = (blogPost) => {
|
169
|
+
const generateDarkColorFromName = (str) => {
|
170
|
+
// Create a hash of the string
|
171
|
+
let hash = 0;
|
172
|
+
for (let i = 0; i < str.length; i++) {
|
173
|
+
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
174
|
+
}
|
175
|
+
// Convert the hash to a color (ensure it's within RGB range)
|
176
|
+
const hue = Math.floor((hash & 0x00FFFFFF) / 0x10000);
|
177
|
+
// Define color ranges for dark red, green, yellow, and others
|
178
|
+
let colorRange;
|
179
|
+
if (hue >= 0 && hue < 30) { // Dark red
|
180
|
+
colorRange = 0; // Red hue
|
181
|
+
}
|
182
|
+
else if (hue >= 30 && hue < 90) { // Dark orange to yellow
|
183
|
+
colorRange = 60; // Yellow hue
|
184
|
+
}
|
185
|
+
else if (hue >= 90 && hue < 150) { // Dark green
|
186
|
+
colorRange = 120; // Green hue
|
187
|
+
}
|
188
|
+
else if (hue >= 150 && hue < 210) { // Dark cyan
|
189
|
+
colorRange = 180; // Cyan hue
|
190
|
+
}
|
191
|
+
else if (hue >= 210 && hue < 270) { // Dark blue
|
192
|
+
colorRange = 240; // Blue hue
|
193
|
+
}
|
194
|
+
else if (hue >= 270 && hue < 330) { // Dark purple
|
195
|
+
colorRange = 300; // Purple hue
|
196
|
+
}
|
197
|
+
else { // Dark magenta
|
198
|
+
colorRange = 360; // Magenta hue
|
199
|
+
}
|
200
|
+
// Use a low lightness value to keep the color dark
|
201
|
+
return `hsl(${colorRange}, 70%, 30%)`; // Low lightness for dark colors
|
202
|
+
};
|
203
|
+
const extractInitialsFromName = (name) => {
|
204
|
+
// If the name has 3 characters, return the first 2 characters
|
205
|
+
if (name.length >= 3) {
|
206
|
+
const lettersOnly = name.replace(/[^a-zA-Z]/g, '');
|
207
|
+
return lettersOnly.substring(0, 3).toUpperCase();
|
208
|
+
}
|
209
|
+
// If only 1 character, return that character
|
210
|
+
return name[0].toUpperCase();
|
211
|
+
};
|
212
|
+
return _jsx(TMTooltip, { content: blogPost.ownerName ?? '-', children: _jsx("div", { style: {
|
213
|
+
width: "40px",
|
214
|
+
height: "40px",
|
215
|
+
borderRadius: "50%",
|
216
|
+
backgroundColor: generateDarkColorFromName(blogPost.ownerName ?? '-'),
|
217
|
+
display: "flex",
|
218
|
+
alignItems: "center",
|
219
|
+
justifyContent: "center",
|
220
|
+
marginRight: "10px",
|
221
|
+
fontWeight: "bold",
|
222
|
+
color: colors.WHITE,
|
223
|
+
fontSize: "18px",
|
224
|
+
}, children: _jsx("span", { style: { fontSize: "12px" }, children: extractInitialsFromName(blogPost.ownerName ?? '-') }) }) });
|
225
|
+
};
|
226
|
+
export const IconAndHeaderElement = (blogPost, iconColor, isSelected, headerClickCallback, searchText) => {
|
227
|
+
return _jsxs("span", { style: { marginLeft: "5px", cursor: blogPost.classID === 'WG' ? "pointer" : "default", display: "inline-flex", alignItems: "center" }, onClick: headerClickCallback, children: [_jsx(TMTooltip, { content: blogPost.classID === 'DS' ? SDKUI_Localizator.Practice : SDKUI_Localizator.WorkGroup, children: blogPost.classID === "DS" ? (_jsx(IconWorkspace, { color: iconColor })) : (_jsx(IconUserGroup, { color: iconColor })) }), _jsx("span", { style: {
|
228
|
+
marginLeft: "5px",
|
229
|
+
textDecoration: blogPost.classID === "WG" ? "underline" : "none",
|
230
|
+
cursor: blogPost.classID === "WG" ? "pointer" : "default",
|
231
|
+
color: isSelected
|
232
|
+
? "#fff"
|
233
|
+
: (blogPost.classID === "WG" ? colors.DARK_BLUE : colors.BLACK),
|
234
|
+
display: "inline-block" // Ensure both elements are in a row
|
235
|
+
}, onClick: headerClickCallback, children: highlightText(blogPost.header ?? '', searchText, isSelected) })] });
|
236
|
+
};
|
237
|
+
export const findFileItemByDraftID = (tree, draftID) => {
|
238
|
+
if (tree === undefined || draftID === undefined)
|
239
|
+
return null;
|
240
|
+
if (tree.id === draftID) {
|
241
|
+
return tree;
|
242
|
+
}
|
243
|
+
if (tree.items && tree.items.length > 0) {
|
244
|
+
for (const item of tree.items) {
|
245
|
+
const found = findFileItemByDraftID(item, draftID);
|
246
|
+
if (found) {
|
247
|
+
return found;
|
248
|
+
}
|
249
|
+
}
|
250
|
+
}
|
251
|
+
return null;
|
252
|
+
};
|
253
|
+
export const isHeaderFullyHidden = (header) => {
|
254
|
+
if (!header) {
|
255
|
+
return true;
|
256
|
+
}
|
257
|
+
return !header.showViewMode && !header.showFilters && !header.showSearchBar && !header.showPostsDropDown;
|
258
|
+
};
|
@@ -41,6 +41,8 @@ export * from './choosers/TMDcmtTypeChooser';
|
|
41
41
|
export * from './choosers/TMMetadataChooser';
|
42
42
|
export * from './choosers/TMUserChooser';
|
43
43
|
export { default as TMValidationItemsList } from './grids/TMValidationItemsList';
|
44
|
+
export { default as TMBlogs } from './grids/TMBlogs';
|
45
|
+
export * from './query/TMDcmtIcon';
|
44
46
|
export * from './query/TMQueryEditor';
|
45
47
|
export * from './query/TMQueryResultForm';
|
46
48
|
export * from './query/TMQuerySummary';
|
package/lib/components/index.js
CHANGED
@@ -45,7 +45,9 @@ export * from './choosers/TMMetadataChooser';
|
|
45
45
|
export * from './choosers/TMUserChooser';
|
46
46
|
//grids
|
47
47
|
export { default as TMValidationItemsList } from './grids/TMValidationItemsList';
|
48
|
+
export { default as TMBlogs } from './grids/TMBlogs';
|
48
49
|
//query
|
50
|
+
export * from './query/TMDcmtIcon';
|
49
51
|
export * from './query/TMQueryEditor';
|
50
52
|
export * from './query/TMQueryResultForm';
|
51
53
|
export * from './query/TMQuerySummary';
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { DcmtInfo } from '../../ts';
|
3
|
+
interface ITMBatchUpdateFormProps {
|
4
|
+
inputDcmts: DcmtInfo[];
|
5
|
+
TID: number | undefined;
|
6
|
+
DID: number | undefined;
|
7
|
+
onBack?: () => void;
|
8
|
+
onSavedCallbackAsync?: () => Promise<void>;
|
9
|
+
onStatusChanged?: (isModified: boolean, isValid: boolean) => void;
|
10
|
+
}
|
11
|
+
declare const TMBatchUpdateForm: React.FC<ITMBatchUpdateFormProps>;
|
12
|
+
export default TMBatchUpdateForm;
|
@@ -0,0 +1,149 @@
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
2
|
+
import { useEffect, useState } from 'react';
|
3
|
+
import { AccessLevels, DcmtTypeListCacheService, LayoutModes, MetadataDataDomains, ResultTypes, SDK_Globals, ValidationItem } from '@topconsultnpm/sdk-ts-beta';
|
4
|
+
import { searchResultToMetadataValues, getSystemMetadata, calcIsModified, getListMaxItems, SDKUI_Localizator, IconHide, IconShow } from '../../helper';
|
5
|
+
import { useDcmtOperations } from '../../hooks/useDcmtOperations';
|
6
|
+
import { DcmtOperationTypes, FormModes } from '../../ts';
|
7
|
+
import { TMColors } from '../../utils/theme';
|
8
|
+
import { StyledToolbarCardContainer, StyledFormButtonsContainer } from '../base/Styled';
|
9
|
+
import TMButton from '../base/TMButton';
|
10
|
+
import { useDeviceType, DeviceType } from '../base/TMDeviceProvider';
|
11
|
+
import { TMSplitterLayout } from '../base/TMLayout';
|
12
|
+
import { TMExceptionBoxManager } from '../base/TMPopUp';
|
13
|
+
import TMShowAllOrMaxItemsButton from '../base/TMShowAllOrMaxItemsButton';
|
14
|
+
import TMSpinner from '../base/TMSpinner';
|
15
|
+
import TMToolbarCard from '../base/TMToolbarCard';
|
16
|
+
import { TMLayoutWaitingContainer } from '../base/TMWaitPanel';
|
17
|
+
import TMDistinctValues from '../choosers/TMDistinctValues';
|
18
|
+
import TMFormulaEditor, { FormulaDescriptor, FormulaHelper, FormulaTargets } from '../editors/TMFormulaEditor';
|
19
|
+
import { useMetadataEditableList } from '../editors/TMMetadataEditor';
|
20
|
+
import TMMetadataValues, { ShowCheckBoxesMode, AdvancedMenuButtons } from '../editors/TMMetadataValues';
|
21
|
+
import { TMSaveFormButtonSave, TMSaveFormButtonUndo } from '../forms/TMSaveForm';
|
22
|
+
const TMBatchUpdateForm = ({ inputDcmts, TID, DID, onSavedCallbackAsync, onBack, onStatusChanged }) => {
|
23
|
+
const [metadataValues, setMetadataValues] = useState([]);
|
24
|
+
const [metadataValuesOrig, setMetadataValuesOrig] = useState([]);
|
25
|
+
const [validationItems, setValidationItems] = useState([]);
|
26
|
+
const [showAll, setShowAll] = useState(false);
|
27
|
+
const [showAdvancedMenu, setShowAdvancedMenu] = useState(false);
|
28
|
+
const [showDistinctValuesPanel, setShowDistinctValuesPanel] = useState(false);
|
29
|
+
const [showFormulaEditor, setShowFormulaEditor] = useState(false);
|
30
|
+
const [focusedMetadataValue, setFocusedMetadataValue] = useState();
|
31
|
+
const [addOrRemoveEditableList] = useMetadataEditableList();
|
32
|
+
const { abortController, runOperationAsync, showWaitPanel, waitPanelTitle, showPrimary, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary } = useDcmtOperations();
|
33
|
+
const deviceType = useDeviceType();
|
34
|
+
useEffect(() => {
|
35
|
+
if (!TID)
|
36
|
+
return;
|
37
|
+
if (!DID)
|
38
|
+
return;
|
39
|
+
if (isModified)
|
40
|
+
return;
|
41
|
+
retrieveMetadataAsync();
|
42
|
+
}, [TID, DID]);
|
43
|
+
useEffect(() => {
|
44
|
+
validateAsync();
|
45
|
+
onStatusChanged?.(isModified, validationItems.findIndex(o => o.ResultType != ResultTypes.SUCCESS) >= 0);
|
46
|
+
}, [metadataValues]);
|
47
|
+
const validateAsync = async () => {
|
48
|
+
let vil = [];
|
49
|
+
if (metadataValues.filter(o => o.isSelected).length <= 0)
|
50
|
+
vil.push(new ValidationItem(ResultTypes.ERROR, "isSelectd", `${'Selezionare almeno un metadato da aggiornare'}`));
|
51
|
+
else {
|
52
|
+
for (const mvd of metadataValues) {
|
53
|
+
if (!mvd.isSelected)
|
54
|
+
continue;
|
55
|
+
if (!mvd.value && !mvd.isNull)
|
56
|
+
vil.push(new ValidationItem(ResultTypes.ERROR, mvd.md?.nameLoc ?? "", `Specificare un valore (${mvd.md?.nameLoc})`));
|
57
|
+
}
|
58
|
+
}
|
59
|
+
setValidationItems(vil);
|
60
|
+
};
|
61
|
+
const retrieveMetadataAsync = async () => {
|
62
|
+
try {
|
63
|
+
await DcmtTypeListCacheService.GetAsync(TID).then(async (dtd) => {
|
64
|
+
let mdList = dtd?.metadata ?? [];
|
65
|
+
await setMetadataListAsync(mdList);
|
66
|
+
});
|
67
|
+
}
|
68
|
+
catch (e) {
|
69
|
+
let err = e;
|
70
|
+
TMExceptionBoxManager.show({ exception: err });
|
71
|
+
}
|
72
|
+
};
|
73
|
+
const setMetadataListAsync = async (mdList) => {
|
74
|
+
try {
|
75
|
+
TMSpinner.show({ description: 'Caricamento metadati...' });
|
76
|
+
let res = await SDK_Globals.tmSession?.NewSearchEngine().GetMetadataAsync(TID, DID, true);
|
77
|
+
let dtd = res?.dtdResult;
|
78
|
+
let rows = dtd.rows ? dtd.rows[0] : [];
|
79
|
+
let mids = res?.selectMIDs;
|
80
|
+
let metadataList = searchResultToMetadataValues(TID, dtd, rows, mids, mdList, LayoutModes.Update)
|
81
|
+
.filter(o => o.md?.dataDomain !== MetadataDataDomains.Computed &&
|
82
|
+
o.md?.perm?.canUpdate === AccessLevels.Yes &&
|
83
|
+
o.md.isSystem !== 1);
|
84
|
+
metadataList.forEach(mvd => { mvd.isSelected = false; mvd.isNull = false; });
|
85
|
+
setMetadataValuesOrig(structuredClone(metadataList));
|
86
|
+
setMetadataValues(structuredClone(metadataList));
|
87
|
+
}
|
88
|
+
catch (e) {
|
89
|
+
TMExceptionBoxManager.show({ exception: e });
|
90
|
+
}
|
91
|
+
finally {
|
92
|
+
TMSpinner.hide();
|
93
|
+
}
|
94
|
+
};
|
95
|
+
const onUndoHandler = () => {
|
96
|
+
setMetadataValues(structuredClone(metadataValuesOrig));
|
97
|
+
};
|
98
|
+
const onSavedAsync = async () => {
|
99
|
+
let dcmts = inputDcmts.slice();
|
100
|
+
dcmts.forEach(o => o.metadataValues = metadataValues);
|
101
|
+
await runOperationAsync(dcmts, DcmtOperationTypes.BatchUpdate, onSavedCallbackAsync);
|
102
|
+
};
|
103
|
+
const getFormula = () => {
|
104
|
+
let fd = new FormulaDescriptor();
|
105
|
+
fd.expression = FormulaHelper.isFormula(focusedMetadataValue?.value) ? FormulaHelper.removeFormulaTag(focusedMetadataValue?.value) : undefined;
|
106
|
+
fd.formulaTarget = FormulaTargets.BatchUpdate;
|
107
|
+
fd.items = FormulaHelper.TreeViewList(TID ?? 0, getSystemMetadata(true), undefined, FormulaTargets.BatchUpdate, SDK_Globals.dbBrand);
|
108
|
+
fd.mid = focusedMetadataValue?.mid ?? 0;
|
109
|
+
fd.tid = TID;
|
110
|
+
return fd;
|
111
|
+
};
|
112
|
+
const isModified = calcIsModified(metadataValues, metadataValuesOrig);
|
113
|
+
const errors = validationItems.filter(o => o.ResultType == ResultTypes.ERROR);
|
114
|
+
const listMaxItems = getListMaxItems(deviceType ?? DeviceType.DESKTOP);
|
115
|
+
const totalItems = metadataValues.filter(o => o.mid && o.mid > 100).length;
|
116
|
+
const metadataValuesSource = metadataValues.filter(o => o.mid && o.mid > 100).slice(0, showAll ? metadataValues.filter(o => o.mid && o.mid > 100).length : listMaxItems);
|
117
|
+
const metadataValuesSourceOrig = metadataValuesOrig.filter(o => o.mid && o.mid > 100).slice(0, showAll ? metadataValuesOrig.filter(o => o.mid && o.mid > 100).length : listMaxItems);
|
118
|
+
return (_jsx(TMLayoutWaitingContainer, { showWaitPanel: showWaitPanel, showWaitPanelPrimary: showPrimary, waitPanelTitle: waitPanelTitle, waitPanelTextPrimary: waitPanelTextPrimary, waitPanelValuePrimary: waitPanelValuePrimary, waitPanelMaxValuePrimary: waitPanelMaxValuePrimary, isCancelable: true, abortController: abortController, children: _jsxs(TMSplitterLayout, { separatorSize: 5, separatorColor: 'transparent', showSeparator: showDistinctValuesPanel || showFormulaEditor, start: showDistinctValuesPanel || showFormulaEditor ? ['50%', '50%'] : ['100%', '0%'], min: ['0', '0'], direction: 'horizontal', children: [_jsx(TMToolbarCard, { title: `${SDKUI_Localizator.BatchUpdate} (${inputDcmts.length} documenti selezionati)`, backgroundColorContainer: TMColors.default_background, toolbar: _jsx(TMButton, { btnStyle: 'icon', icon: showAdvancedMenu ? _jsx(IconHide, { color: 'white' }) : _jsx(IconShow, { color: 'white' }), caption: showAdvancedMenu ? SDKUI_Localizator.StandardMode : SDKUI_Localizator.ExpertMode, onClick: () => setShowAdvancedMenu(!showAdvancedMenu) }), onBack: deviceType === DeviceType.MOBILE ? onBack : undefined, onClose: deviceType !== DeviceType.MOBILE ? onBack : undefined, children: _jsxs(StyledToolbarCardContainer, { children: [_jsx(TMMetadataValues, { TID: TID, showAdvancedMenu: showAdvancedMenu, showCheckBoxes: ShowCheckBoxesMode.Always, showNullValueCheckBoxes: true, metadataValues: metadataValuesSource, metadataValuesOrig: metadataValuesSourceOrig, validationItems: validationItems, isOpenDistinctValues: showDistinctValuesPanel, selectedMID: focusedMetadataValue?.mid, onFocusedItemChanged: (item) => { setFocusedMetadataValue(item); }, onValueChanged: (newItems) => {
|
119
|
+
setMetadataValues((prevItems) => prevItems.map((item) => {
|
120
|
+
const newItem = newItems.find((newItem) => newItem.tid === item.tid && newItem.mid === item.mid);
|
121
|
+
return newItem ? { ...item, ...newItem } : item;
|
122
|
+
}));
|
123
|
+
}, onAdvancedMenuClick: (e) => {
|
124
|
+
switch (e.button) {
|
125
|
+
case AdvancedMenuButtons.DistinctValues:
|
126
|
+
setShowDistinctValuesPanel(!showDistinctValuesPanel);
|
127
|
+
break;
|
128
|
+
case AdvancedMenuButtons.FormulaEditor:
|
129
|
+
setShowFormulaEditor(!showFormulaEditor);
|
130
|
+
break;
|
131
|
+
}
|
132
|
+
} }), _jsxs(StyledFormButtonsContainer, { children: [_jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: 10 }, children: _jsxs("div", { style: { display: 'flex', justifyContent: 'center', alignItems: 'center', gap: '8px' }, children: [_jsx(TMSaveFormButtonSave, { showTooltip: false, btnStyle: 'advanced', advancedColor: '#f09c0a', isModified: errors.length <= 0 && isModified, formMode: FormModes.Update, errorsCount: errors.length, onSaveAsync: onSavedAsync }), _jsx(TMSaveFormButtonUndo, { btnStyle: 'toolbar', showTooltip: true, color: 'primary', isModified: isModified, formMode: FormModes.Update, onUndo: onUndoHandler })] }) }), totalItems > listMaxItems && _jsx(TMShowAllOrMaxItemsButton, { showAll: showAll, dataSourceLength: totalItems, onClick: () => { setShowAll(!showAll); } })] })] }) }), showDistinctValuesPanel && focusedMetadataValue &&
|
133
|
+
_jsx(TMDistinctValues, { tid: TID, mid: focusedMetadataValue?.mid, separator: ', ', allowAppendMode: false, onClosePanelCallback: () => setShowDistinctValuesPanel(false), onSelectionChanged: (e) => {
|
134
|
+
if (!e)
|
135
|
+
return;
|
136
|
+
setMetadataValues((prevItems) => prevItems.map((item) => item.tid == e.tid && item.mid === e.mid ? { ...item, value: e.newValue, isSelected: true } : item));
|
137
|
+
} }), showFormulaEditor && focusedMetadataValue &&
|
138
|
+
_jsx(TMToolbarCard, { title: SDKUI_Localizator.FormulaEditorTitle + (focusedMetadataValue?.md?.nameLoc ? ` (${focusedMetadataValue?.md?.nameLoc})` : ''), onClose: () => setShowFormulaEditor(false), children: _jsx(TMFormulaEditor, { isModal: false, formMode: FormModes.Update, inputData: getFormula(), showBack: false, onClose: () => setShowFormulaEditor(false), onApplied: (newFormula) => {
|
139
|
+
setMetadataValues((prevItems) => prevItems.map((item) => item.tid == newFormula.tid && item.mid === newFormula.mid ? { ...item, value: FormulaHelper.addFormulaTag(newFormula.expression), isSelected: true, isEditable: true } : item));
|
140
|
+
setFocusedMetadataValue(prevState => ({
|
141
|
+
...prevState,
|
142
|
+
isSelected: true,
|
143
|
+
isEditable: true,
|
144
|
+
value: FormulaHelper.addFormulaTag(newFormula.expression)
|
145
|
+
}));
|
146
|
+
addOrRemoveEditableList(newFormula.mid);
|
147
|
+
} }) })] }) }));
|
148
|
+
};
|
149
|
+
export default TMBatchUpdateForm;
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
2
|
+
import { SDK_Globals } from '@topconsultnpm/sdk-ts-beta';
|
3
|
+
import { useEffect, useState } from 'react';
|
4
|
+
import styled from 'styled-components';
|
5
|
+
import { TMExceptionBoxManager } from '../base/TMPopUp';
|
6
|
+
import TMSpinner from '../base/TMSpinner';
|
7
|
+
import TMBlogs from '../grids/TMBlogs';
|
8
|
+
const TMDcmtBlog = ({ tid, did }) => {
|
9
|
+
const [blogsDatasource, setBlogsDatasource] = useState([]);
|
10
|
+
useEffect(() => {
|
11
|
+
if (!tid || !did)
|
12
|
+
return;
|
13
|
+
loadDataAsync(tid, did);
|
14
|
+
}, [did]);
|
15
|
+
const loadDataAsync = async (tid, did) => {
|
16
|
+
try {
|
17
|
+
TMSpinner.show({ description: 'Caricamento - Bacheca...' });
|
18
|
+
let res = await SDK_Globals.tmSession?.NewSearchEngine().BlogRetrieveAsync(tid, did);
|
19
|
+
setBlogsDatasource(res ?? []);
|
20
|
+
}
|
21
|
+
catch (e) {
|
22
|
+
let err = e;
|
23
|
+
TMExceptionBoxManager.show({ exception: err });
|
24
|
+
}
|
25
|
+
finally {
|
26
|
+
TMSpinner.hide();
|
27
|
+
}
|
28
|
+
};
|
29
|
+
return (_jsx(StyledContainer, { children: _jsx(StyledSectionContainer, { style: { position: 'relative' }, children: _jsx(StyledBoardContainer, { children: _jsx(TMBlogs, { id: "dcmt-blog", allData: blogsDatasource, showExtendedAttachments: false }) }) }) }));
|
30
|
+
};
|
31
|
+
export default TMDcmtBlog;
|
32
|
+
const StyledContainer = styled.div ` user-select: none; overflow: hidden; background-color: #ffffff; width: calc(100%); height: calc(100%); display: flex; gap: 10px; `;
|
33
|
+
const StyledSectionContainer = styled.div ` width: 100%; height: 100%; display:flex; flex-direction: column; `;
|
34
|
+
const StyledBoardContainer = styled.div `width: 100%; height: 100%; padding: 10px;`;
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { LayoutModes } from '@topconsultnpm/sdk-ts-beta';
|
3
|
+
import { FormModes } from '../../ts';
|
4
|
+
import { ITMRightSidebarItem } from '../base/TMRightSidebar';
|
5
|
+
interface ITMDcmtFormProps {
|
6
|
+
TID?: number;
|
7
|
+
DID?: number;
|
8
|
+
layoutMode?: LayoutModes;
|
9
|
+
formMode?: FormModes;
|
10
|
+
allowNavigation?: boolean;
|
11
|
+
allowRelations?: boolean;
|
12
|
+
showHeader?: boolean;
|
13
|
+
showDcmtForm?: boolean;
|
14
|
+
showPreview?: boolean;
|
15
|
+
showBoard?: boolean;
|
16
|
+
showSysMetadata?: boolean;
|
17
|
+
customRightSidebarItems?: ITMRightSidebarItem[];
|
18
|
+
showDcmtFormSidebar?: boolean;
|
19
|
+
count?: number;
|
20
|
+
itemIndex?: number;
|
21
|
+
canNext?: boolean;
|
22
|
+
canPrev?: boolean;
|
23
|
+
isClosable?: boolean;
|
24
|
+
onNext?: () => void;
|
25
|
+
onPrev?: () => void;
|
26
|
+
onClose?: () => void;
|
27
|
+
onSavedAsyncCallback?: (tid: number | undefined, did: number | undefined) => Promise<void>;
|
28
|
+
onSaveRecents?: (TIDs: number[]) => void;
|
29
|
+
onClosePreview?: () => void;
|
30
|
+
}
|
31
|
+
declare const TMDcmtForm: React.FC<ITMDcmtFormProps>;
|
32
|
+
export default TMDcmtForm;
|